diff options
Diffstat (limited to 'test')
344 files changed, 27492 insertions, 3344 deletions
diff --git a/test/all.test b/test/all.test index 54302d0..f6e722f 100644 --- a/test/all.test +++ b/test/all.test @@ -39,6 +39,7 @@ run_test_suite pcache50 run_test_suite pcache90 run_test_suite pcache100 run_test_suite prepare +run_test_suite mmap if {$::tcl_platform(platform)=="unix"} { ifcapable !default_autovacuum { @@ -47,5 +48,3 @@ if {$::tcl_platform(platform)=="unix"} { } finish_test - - diff --git a/test/alter.test b/test/alter.test index aca71c4..ddf1698 100644 --- a/test/alter.test +++ b/test/alter.test @@ -847,7 +847,8 @@ do_test alter-14.2 { set system_table_list {1 sqlite_master} catchsql ANALYZE ifcapable analyze { lappend system_table_list 2 sqlite_stat1 } -ifcapable stat3 { lappend system_table_list 4 sqlite_stat3 } +ifcapable stat3 { lappend system_table_list 3 sqlite_stat3 } +ifcapable stat4 { lappend system_table_list 4 sqlite_stat4 } foreach {tn tbl} $system_table_list { do_test alter-15.$tn.1 { @@ -859,5 +860,57 @@ foreach {tn tbl} $system_table_list { } [list 1 "table $tbl may not be altered"] } +#------------------------------------------------------------------------ +# Verify that ALTER TABLE works on tables with the WITHOUT rowid option. +# +do_execsql_test alter-16.1 { + CREATE TABLE t16a(a TEXT, b REAL, c INT, PRIMARY KEY(a,b)) WITHOUT rowid; + INSERT INTO t16a VALUES('abc',1.25,99); + ALTER TABLE t16a ADD COLUMN d TEXT DEFAULT 'xyzzy'; + INSERT INTO t16a VALUES('cba',5.5,98,'fizzle'); + SELECT * FROM t16a ORDER BY a; +} {abc 1.25 99 xyzzy cba 5.5 98 fizzle} +do_execsql_test alter-16.2 { + ALTER TABLE t16a RENAME TO t16a_rn; + SELECT * FROM t16a_rn ORDER BY a; +} {abc 1.25 99 xyzzy cba 5.5 98 fizzle} + +#------------------------------------------------------------------------- +# Verify that NULL values into the internal-use-only sqlite_rename_*() +# functions do not cause problems. +# +do_execsql_test alter-17.1 { + SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)','abc'); +} {{CREATE TABLE "abc"(a,b,c)}} +do_execsql_test alter-17.2 { + SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)',NULL); +} {{CREATE TABLE "(NULL)"(a,b,c)}} +do_execsql_test alter-17.3 { + SELECT sqlite_rename_table(NULL,'abc'); +} {{}} +do_execsql_test alter-17.4 { + SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN','abc'); +} {{CREATE TRIGGER r1 ON "abc" WHEN}} +do_execsql_test alter-17.5 { + SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN',NULL); +} {{CREATE TRIGGER r1 ON "(NULL)" WHEN}} +do_execsql_test alter-17.6 { + SELECT sqlite_rename_trigger(NULL,'abc'); +} {{}} +do_execsql_test alter-17.7 { + SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")', + 'xyzzy','lmnop'); +} {{CREATE TABLE t1(a REFERENCES "lmnop")}} +do_execsql_test alter-17.8 { + SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")', + 'xyzzy',NULL); +} {{CREATE TABLE t1(a REFERENCES "(NULL)")}} +do_execsql_test alter-17.9 { + SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")', + NULL, 'lmnop'); +} {{}} +do_execsql_test alter-17.10 { + SELECT sqlite_rename_parent(NULL,'abc','xyz'); +} {{}} finish_test diff --git a/test/alter4.test b/test/alter4.test index cda4553..eaad37e 100644 --- a/test/alter4.test +++ b/test/alter4.test @@ -143,6 +143,11 @@ do_test alter4-2.6 { alter table t1 add column d DEFAULT CURRENT_TIME; } } {1 {Cannot add a column with non-constant default}} +do_test alter4-2.7 { + catchsql { + alter table t1 add column d default (-+1); + } +} {1 {Cannot add a column with non-constant default}} do_test alter4-2.99 { execsql { DROP TABLE t1; @@ -329,4 +334,25 @@ do_test alter4-8.2 { } } [list $::sql] + +# Test that a default value equal to -1 multipied by the smallest possible +# 64-bit integer is correctly converted to a real. +do_execsql_test alter4-9.1 { + CREATE TABLE t5( + a INTEGER DEFAULT -9223372036854775808, + b INTEGER DEFAULT (-(-9223372036854775808)) + ); + INSERT INTO t5 DEFAULT VALUES; +} + +do_execsql_test alter4-9.2 { SELECT typeof(a), a, typeof(b), b FROM t5; } { + integer -9223372036854775808 + real 9.22337203685478e+18 +} + +do_execsql_test alter4-9.3 { + ALTER TABLE t5 ADD COLUMN c INTEGER DEFAULT (-(-9223372036854775808)); + SELECT typeof(c), c FROM t5; +} {real 9.22337203685478e+18} + finish_test diff --git a/test/amatch1.test b/test/amatch1.test new file mode 100644 index 0000000..cc0f77a --- /dev/null +++ b/test/amatch1.test @@ -0,0 +1,117 @@ +# 2013-09-30 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for "approximate_match" virtual +# table that is in the "amatch.c" extension. +# +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# If SQLITE_ENABLE_FTS4 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +# Create the fts_kjv_genesis procedure which fills and FTS3/4 table with +# the complete text of the Book of Genesis. +# +source $testdir/genesis.tcl + + + +do_test amatch1-1.0 { + db eval { + CREATE VIRTUAL TABLE t1 USING fts4(words); --, tokenize porter); + } + fts_kjv_genesis + db eval { + INSERT INTO t1(t1) VALUES('optimize'); + CREATE VIRTUAL TABLE temp.t1aux USING fts4aux(main, t1); + SELECT term FROM t1aux WHERE col=0 ORDER BY 1 LIMIT 5 + } +} {a abated abel abelmizraim abidah} +do_test amatch1-1.1 { + db eval { + SELECT term FROM t1aux WHERE term>'b' AND col=0 ORDER BY 1 LIMIT 5 + } +} {baalhanan babel back backward bad} +do_test amatch1-1.2 { + db eval { + SELECT term FROM t1aux WHERE term>'b' AND col=0 LIMIT 5 + } +} {baalhanan babel back backward bad} + +# Load the amatch extension +load_static_extension db amatch + +do_execsql_test amatch1-2.0 { + CREATE TABLE costs(iLang, cFrom, cTo, Cost); + INSERT INTO costs VALUES(0, '', '?', 100); + INSERT INTO costs VALUES(0, '?', '', 100); + INSERT INTO costs VALUES(0, '?', '?', 150); + CREATE TABLE vocab(w TEXT UNIQUE); + INSERT OR IGNORE INTO vocab SELECT term FROM t1aux; + CREATE VIRTUAL TABLE t2 USING approximate_match( + vocabulary_table=t1aux, + vocabulary_word=term, + edit_distances=costs + ); + CREATE VIRTUAL TABLE t3 USING approximate_match( + vocabulary_table=vocab, + vocabulary_word=w, + edit_distances=costs + ); + CREATE VIRTUAL TABLE t4 USING approximate_match( + vocabulary_table=vtemp, + vocabulary_word=w, + edit_distances=costs + ); +} {} +puts "Query against fts4aux: [time { + do_execsql_test amatch1-2.1 { + SELECT word, distance FROM t2 + WHERE word MATCH 'josxph' AND distance<300; + } {joseph 150}} 1]" +puts "Query against ordinary table: [time { + do_execsql_test amatch1-2.2 { + SELECT word, distance FROM t3 + WHERE word MATCH 'josxph' AND distance<300; + } {joseph 150}} 1]" +puts "Temp table initialized from fts4aux: [time { + do_execsql_test amatch1-2.3a { + CREATE TEMP TABLE vtemp(w TEXT UNIQUE); + INSERT OR IGNORE INTO vtemp SELECT term FROM t1aux; + } {}} 1]" +puts "Query against temp table: [time { + do_execsql_test amatch1-2.3b { + SELECT word, distance FROM t4 + WHERE word MATCH 'josxph' AND distance<300; + } {joseph 150}} 1]" +do_execsql_test amatch1-2.11 { + SELECT word, distance FROM t2 + WHERE word MATCH 'joxxph' AND distance<=300; +} {joseph 300} +do_execsql_test amatch1-2.12 { + SELECT word, distance FROM t3 + WHERE word MATCH 'joxxph' AND distance<=300; +} {joseph 300} +do_execsql_test amatch1-2.21 { + SELECT word, distance FROM t2 + WHERE word MATCH 'joxxph' AND distance<300; +} {} +do_execsql_test amatch1-2.22 { + SELECT word, distance FROM t3 + WHERE word MATCH 'joxxph' AND distance<300; +} {} + +finish_test diff --git a/test/analyze.test b/test/analyze.test index 362702a..c445084 100644 --- a/test/analyze.test +++ b/test/analyze.test @@ -288,7 +288,7 @@ do_test analyze-4.3 { } {} # Verify that DROP TABLE and DROP INDEX remove entries from the -# sqlite_stat1 and sqlite_stat3 tables. +# sqlite_stat1, sqlite_stat3 and sqlite_stat4 tables. # do_test analyze-5.0 { execsql { @@ -306,12 +306,13 @@ do_test analyze-5.0 { SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1; } } {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4} -ifcapable stat3 { +ifcapable stat4||stat3 { + ifcapable stat4 {set stat sqlite_stat4} else {set stat sqlite_stat3} do_test analyze-5.1 { - execsql { - SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1; - SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1; - } + execsql " + SELECT DISTINCT idx FROM $stat ORDER BY 1; + SELECT DISTINCT tbl FROM $stat ORDER BY 1; + " } {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4} } do_test analyze-5.2 { @@ -321,12 +322,12 @@ do_test analyze-5.2 { SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1; } } {t3i1 t3i3 t4i1 t4i2 t3 t4} -ifcapable stat3 { +ifcapable stat4||stat3 { do_test analyze-5.3 { - execsql { - SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1; - SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1; - } + execsql " + SELECT DISTINCT idx FROM $stat ORDER BY 1; + SELECT DISTINCT tbl FROM $stat ORDER BY 1; + " } {t3i1 t3i3 t4i1 t4i2 t3 t4} } do_test analyze-5.4 { @@ -336,12 +337,12 @@ do_test analyze-5.4 { SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1; } } {t4i1 t4i2 t4} -ifcapable stat3 { +ifcapable stat4||stat3 { do_test analyze-5.5 { - execsql { - SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1; - SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1; - } + execsql " + SELECT DISTINCT idx FROM $stat ORDER BY 1; + SELECT DISTINCT tbl FROM $stat ORDER BY 1; + " } {t4i1 t4i2 t4} } @@ -360,5 +361,4 @@ do_test analyze-99.1 { } } {1 {malformed database schema (sqlite_stat1) - near "nonsense": syntax error}} - finish_test diff --git a/test/analyze3.test b/test/analyze3.test index f705bc6..e7416d5 100644 --- a/test/analyze3.test +++ b/test/analyze3.test @@ -17,7 +17,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !stat3 { +ifcapable !stat4&&!stat3 { finish_test return } @@ -43,6 +43,8 @@ ifcapable !stat3 { # analyze3-5.*: Check that the query plans of applicable statements are # invalidated if the values of SQL parameter are modified # using the clear_bindings() or transfer_bindings() APIs. +# +# analyze3-6.*: Test that the problem fixed by commit [127a5b776d] is fixed. # proc getvar {varname} { uplevel #0 set $varname } @@ -93,14 +95,29 @@ do_test analyze3-1.1.1 { COMMIT; ANALYZE; } -} {} + ifcapable stat4 { + execsql { SELECT count(*)>0 FROM sqlite_stat4; } + } else { + execsql { SELECT count(*)>0 FROM sqlite_stat3; } + } +} {1} + +do_execsql_test analyze3-1.1.x { + SELECT count(*) FROM t1 WHERE x>200 AND x<300; + SELECT count(*) FROM t1 WHERE x>0 AND x<1100; +} {99 1000} + +# The first of the following two SELECT statements visits 99 rows. So +# it is better to use the index. But the second visits every row in +# the table (1000 in total) so it is better to do a full-table scan. +# do_eqp_test analyze3-1.1.2 { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?) (~179 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}} do_eqp_test analyze3-1.1.3 { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?) (~959 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_test analyze3-1.1.4 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } @@ -117,17 +134,17 @@ do_test analyze3-1.1.6 { } {199 0 14850} do_test analyze3-1.1.7 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 } -} {2000 0 499500} +} {999 999 499500} do_test analyze3-1.1.8 { set l [string range "0" 0 end] set u [string range "1100" 0 end] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } -} {2000 0 499500} +} {999 999 499500} do_test analyze3-1.1.9 { set l [expr int(0)] set u [expr int(1100)] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } -} {2000 0 499500} +} {999 999 499500} # The following tests are similar to the block above. The difference is @@ -144,12 +161,17 @@ do_test analyze3-1.2.1 { ANALYZE; } } {} +do_execsql_test analyze3-2.1.x { + SELECT count(*) FROM t2 WHERE x>1 AND x<2; + SELECT count(*) FROM t2 WHERE x>0 AND x<99; +} {200 990} do_eqp_test analyze3-1.2.2 { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 -} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?) (~196 rows)}} +} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}} do_eqp_test analyze3-1.2.3 { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 -} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?) (~968 rows)}} +} {0 0 0 {SCAN TABLE t2}} + do_test analyze3-1.2.4 { sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 } } {161 0 4760} @@ -165,17 +187,17 @@ do_test analyze3-1.2.6 { } {161 0 integer integer 4760} do_test analyze3-1.2.7 { sf_execsql { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 } -} {1981 0 490555} +} {999 999 490555} do_test analyze3-1.2.8 { set l [string range "0" 0 end] set u [string range "99" 0 end] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} -} {1981 0 text text 490555} +} {999 999 text text 490555} do_test analyze3-1.2.9 { set l [expr int(0)] set u [expr int(99)] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} -} {1981 0 integer integer 490555} +} {999 999 integer integer 490555} # Same tests a third time. This time, column x has INTEGER affinity and # is not the leftmost column of the table. This triggered a bug causing @@ -191,12 +213,16 @@ do_test analyze3-1.3.1 { ANALYZE; } } {} +do_execsql_test analyze3-1.3.x { + SELECT count(*) FROM t3 WHERE x>200 AND x<300; + SELECT count(*) FROM t3 WHERE x>0 AND x<1100 +} {99 1000} do_eqp_test analyze3-1.3.2 { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 -} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?) (~156 rows)}} +} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}} do_eqp_test analyze3-1.3.3 { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 -} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?) (~989 rows)}} +} {0 0 0 {SCAN TABLE t3}} do_test analyze3-1.3.4 { sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } @@ -213,17 +239,17 @@ do_test analyze3-1.3.6 { } {199 0 14850} do_test analyze3-1.3.7 { sf_execsql { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 } -} {2000 0 499500} +} {999 999 499500} do_test analyze3-1.3.8 { set l [string range "0" 0 end] set u [string range "1100" 0 end] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } -} {2000 0 499500} +} {999 999 499500} do_test analyze3-1.3.9 { set l [expr int(0)] set u [expr int(1100)] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } -} {2000 0 499500} +} {999 999 499500} #------------------------------------------------------------------------- # Test that the values of bound SQL variables may be used for the LIKE @@ -248,10 +274,10 @@ do_test analyze3-2.1 { } {} do_eqp_test analyze3-2.2 { SELECT count(a) FROM t1 WHERE b LIKE 'a%' -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?) (~31250 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?)}} do_eqp_test analyze3-2.3 { SELECT count(a) FROM t1 WHERE b LIKE '%a' -} {0 0 0 {SCAN TABLE t1 (~500000 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_test analyze3-2.4 { sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE 'a%' } @@ -310,7 +336,6 @@ do_test analyze3-3.1 { execsql COMMIT execsql ANALYZE } {} - do_test analyze3-3.2.1 { set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b>?" -1 dummy] sqlite3_expired $S @@ -330,7 +355,7 @@ do_test analyze3-3.2.5 { do_test analyze3-3.2.6 { sqlite3_bind_text $S 1 "abc" 3 sqlite3_expired $S -} {0} +} {1} do_test analyze3-3.2.7 { sqlite3_finalize $S } {SQLITE_OK} @@ -612,4 +637,29 @@ do_test analyze3-5.1.3 { sqlite3_finalize $S1 } {SQLITE_OK} +#------------------------------------------------------------------------- + +do_test analyze3-6.1 { + execsql { DROP TABLE IF EXISTS t1 } + execsql BEGIN + execsql { CREATE TABLE t1(a, b, c) } + for {set i 0} {$i < 1000} {incr i} { + execsql "INSERT INTO t1 VALUES([expr $i/100], 'x', [expr $i/10])" + } + execsql { + CREATE INDEX i1 ON t1(a, b); + CREATE INDEX i2 ON t1(c); + } + execsql COMMIT + execsql ANALYZE +} {} + +do_eqp_test analyze3-6-3 { + SELECT * FROM t1 WHERE a = 5 AND c = 13; +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}} + +do_eqp_test analyze3-6-2 { + SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13; +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}} + finish_test diff --git a/test/analyze4.test b/test/analyze4.test index 1fed564..974ed89 100644 --- a/test/analyze4.test +++ b/test/analyze4.test @@ -38,7 +38,7 @@ do_test analyze4-1.0 { # Should choose the t1a index since it is more specific than t1b. db eval {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=5 AND b IS NULL} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} # Verify that the t1b index shows that it does not narrow down the # search any at all. diff --git a/test/analyze5.test b/test/analyze5.test index 1041d70..ac175c0 100644 --- a/test/analyze5.test +++ b/test/analyze5.test @@ -10,14 +10,14 @@ #*********************************************************************** # # This file implements tests for SQLite library. The focus of the tests -# in this file is the use of the sqlite_stat3 histogram data on tables +# in this file is the use of the sqlite_stat4 histogram data on tables # with many repeated values and only a few distinct values. # set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !stat3 { +ifcapable !stat4&&!stat3 { finish_test return } @@ -28,6 +28,17 @@ proc eqp {sql {db db}} { uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db } +proc alpha {blob} { + set ret "" + foreach c [split $blob {}] { + if {[string is alpha $c]} {append ret $c} + } + return $ret +} +db func alpha alpha + +db func lindex lindex + unset -nocomplain i t u v w x y z do_test analyze5-1.0 { db eval {CREATE TABLE t1(t,u,v TEXT COLLATE nocase,w,x,y,z)} @@ -55,17 +66,40 @@ do_test analyze5-1.0 { CREATE INDEX t1y ON t1(y); -- integers 0 and very few 1s CREATE INDEX t1z ON t1(z); -- integers 0, 1, 2, and 3 ANALYZE; - SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt; + } + ifcapable stat4 { + db eval { + SELECT DISTINCT lindex(test_decode(sample),0) + FROM sqlite_stat4 WHERE idx='t1u' ORDER BY nlt; + } + } else { + db eval { + SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt; + } } } {alpha bravo charlie delta} do_test analyze5-1.1 { - db eval {SELECT DISTINCT lower(sample) FROM sqlite_stat3 WHERE idx='t1v' - ORDER BY 1} + ifcapable stat4 { + db eval { + SELECT DISTINCT lower(lindex(test_decode(sample), 0)) + FROM sqlite_stat4 WHERE idx='t1v' ORDER BY 1 + } + } else { + db eval { + SELECT lower(sample) FROM sqlite_stat3 WHERE idx='t1v' ORDER BY 1 + } + } } {alpha bravo charlie delta} -do_test analyze5-1.2 { - db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1} -} {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4} +ifcapable stat4 { + do_test analyze5-1.2 { + db eval {SELECT idx, count(*) FROM sqlite_stat4 GROUP BY 1 ORDER BY 1} + } {t1t 8 t1u 8 t1v 8 t1w 8 t1x 8 t1y 9 t1z 8} +} else { + do_test analyze5-1.2 { + db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1} + } {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4} +} # Verify that range queries generate the correct row count estimates # @@ -156,13 +190,14 @@ foreach {testid where index rows} { } { # Verify that the expected index is used with the expected row count - do_test analyze5-1.${testid}a { - set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3] - set idx {} - regexp {INDEX (t1.) } $x all idx - regexp {~([0-9]+) rows} $x all nrow - list $idx $nrow - } [list $index $rows] + # No longer valid due to an EXPLAIN QUERY PLAN output format change + # do_test analyze5-1.${testid}a { + # set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3] + # set idx {} + # regexp {INDEX (t1.) } $x all idx + # regexp {~([0-9]+) rows} $x all nrow + # list $idx $nrow + # } [list $index $rows] # Verify that the same result is achieved regardless of whether or not # the index is used @@ -202,15 +237,14 @@ foreach {testid where index rows} { } { # Verify that the expected index is used with the expected row count -if {$testid==50299} {breakpoint; set sqlite_where_trace 1} - do_test analyze5-1.${testid}a { - set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3] - set idx {} - regexp {INDEX (t1.) } $x all idx - regexp {~([0-9]+) rows} $x all nrow - list $idx $nrow - } [list $index $rows] -if {$testid==50299} exit + # No longer valid due to an EXPLAIN QUERY PLAN format change + # do_test analyze5-1.${testid}a { + # set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3] + # set idx {} + # regexp {INDEX (t1.) } $x all idx + # regexp {~([0-9]+) rows} $x all nrow + # list $idx $nrow + # } [list $index $rows] # Verify that the same result is achieved regardless of whether or not # the index is used diff --git a/test/analyze6.test b/test/analyze6.test index eaa9d73..31ace8e 100644 --- a/test/analyze6.test +++ b/test/analyze6.test @@ -17,7 +17,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !stat3 { +ifcapable !stat4&&!stat3 { finish_test return } @@ -30,14 +30,14 @@ proc eqp {sql {db db}} { do_test analyze6-1.0 { db eval { - CREATE TABLE cat(x INT); + CREATE TABLE cat(x INT, yz TEXT); CREATE UNIQUE INDEX catx ON cat(x); /* Give cat 16 unique integers */ - INSERT INTO cat VALUES(1); - INSERT INTO cat VALUES(2); - INSERT INTO cat SELECT x+2 FROM cat; - INSERT INTO cat SELECT x+4 FROM cat; - INSERT INTO cat SELECT x+8 FROM cat; + INSERT INTO cat(x) VALUES(1); + INSERT INTO cat(x) VALUES(2); + INSERT INTO cat(x) SELECT x+2 FROM cat; + INSERT INTO cat(x) SELECT x+4 FROM cat; + INSERT INTO cat(x) SELECT x+8 FROM cat; CREATE TABLE ev(y INT); CREATE INDEX evy ON ev(y); @@ -61,14 +61,14 @@ do_test analyze6-1.0 { # do_test analyze6-1.1 { eqp {SELECT count(*) FROM ev, cat WHERE x=y} -} {0 0 1 {SCAN TABLE cat USING COVERING INDEX catx (~16 rows)} 0 1 0 {SEARCH TABLE ev USING COVERING INDEX evy (y=?) (~32 rows)}} +} {0 0 1 {SCAN TABLE cat USING COVERING INDEX catx} 0 1 0 {SEARCH TABLE ev USING COVERING INDEX evy (y=?)}} # The same plan is chosen regardless of the order of the tables in the # FROM clause. # do_test analyze6-1.2 { eqp {SELECT count(*) FROM cat, ev WHERE x=y} -} {0 0 0 {SCAN TABLE cat USING COVERING INDEX catx (~16 rows)} 0 1 1 {SEARCH TABLE ev USING COVERING INDEX evy (y=?) (~32 rows)}} +} {0 0 0 {SCAN TABLE cat USING COVERING INDEX catx} 0 1 1 {SEARCH TABLE ev USING COVERING INDEX evy (y=?)}} # Ticket [83ea97620bd3101645138b7b0e71c12c5498fe3d] 2011-03-30 @@ -82,26 +82,26 @@ do_test analyze6-2.1 { ANALYZE; } eqp {SELECT * FROM t201 WHERE z=5} -} {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?)}} do_test analyze6-2.2 { eqp {SELECT * FROM t201 WHERE y=5} -} {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)}} do_test analyze6-2.3 { eqp {SELECT * FROM t201 WHERE x=5} -} {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}} do_test analyze6-2.4 { execsql { - INSERT INTO t201 VALUES(1,2,3); + INSERT INTO t201 VALUES(1,2,3),(2,3,4),(3,4,5); ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} -} {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?)}} do_test analyze6-2.5 { eqp {SELECT * FROM t201 WHERE y=5} -} {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)}} do_test analyze6-2.6 { eqp {SELECT * FROM t201 WHERE x=5} -} {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}} do_test analyze6-2.7 { execsql { INSERT INTO t201 VALUES(4,5,7); @@ -111,12 +111,12 @@ do_test analyze6-2.7 { ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} -} {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?)}} do_test analyze6-2.8 { eqp {SELECT * FROM t201 WHERE y=5} -} {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)}} do_test analyze6-2.9 { eqp {SELECT * FROM t201 WHERE x=5} -} {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}} finish_test diff --git a/test/analyze7.test b/test/analyze7.test index 46ec39e..7666454 100644 --- a/test/analyze7.test +++ b/test/analyze7.test @@ -37,13 +37,13 @@ do_test analyze7-1.0 { WHERE value BETWEEN 1 AND 256; EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123; } -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test analyze7-1.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test analyze7-1.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} # Run an analyze on one of the three indices. Verify that this # effects the row-count estimate on the one query that uses that @@ -53,20 +53,20 @@ do_test analyze7-2.0 { execsql {ANALYZE t1a;} db cache flush execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test analyze7-2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test analyze7-2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} # Verify that since the query planner now things that t1a is more # selective than t1b, it prefers to use t1a. # do_test analyze7-2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} # Run an analysis on another of the three indices. Verify that this # new analysis works and does not disrupt the previous analysis. @@ -75,39 +75,40 @@ do_test analyze7-3.0 { execsql {ANALYZE t1cd;} db cache flush; execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test analyze7-3.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test analyze7-3.2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~86 rows)}} -ifcapable stat3 { - # If ENABLE_STAT3 is defined, SQLite comes up with a different estimated +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} +ifcapable stat4||stat3 { + # If ENABLE_STAT4 is defined, SQLite comes up with a different estimated # row count for (c=2) than it does for (c=?). do_test analyze7-3.2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} - } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~57 rows)}} + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} } else { - # If ENABLE_STAT3 is not defined, the expected row count for (c=2) is the + # If ENABLE_STAT4 is not defined, the expected row count for (c=2) is the # same as that for (c=?). do_test analyze7-3.2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} - } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~86 rows)}} + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} } do_test analyze7-3.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} -ifcapable {!stat3} { +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} + +ifcapable {!stat4 && !stat3} { do_test analyze7-3.4 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123} - } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}} + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test analyze7-3.5 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123} - } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} } do_test analyze7-3.6 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND d=123 AND b=123} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?)}} finish_test diff --git a/test/analyze8.test b/test/analyze8.test index f3e2710..4384c39 100644 --- a/test/analyze8.test +++ b/test/analyze8.test @@ -16,7 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !stat3 { +ifcapable !stat4&&!stat3 { finish_test return } @@ -61,43 +61,55 @@ do_test 1.0 { # do_test 1.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b=55} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test 1.2 { eqp {SELECT * FROM t1 WHERE a=99 AND b=55} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 1.3 { eqp {SELECT * FROM t1 WHERE a=101 AND b=55} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 1.4 { eqp {SELECT * FROM t1 WHERE a=100 AND b=56} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test 1.5 { eqp {SELECT * FROM t1 WHERE a=99 AND b=56} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 1.6 { eqp {SELECT * FROM t1 WHERE a=101 AND b=56} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 2.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b BETWEEN 50 AND 54} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}} # There are many more values of c between 0 and 100000 than there are # between 800000 and 900000. So t1c is more selective for the latter # range. +# +# Test 3.2 is a little unstable. It depends on the planner estimating +# that (b BETWEEN 50 AND 54) will match more rows than (c BETWEEN +# 800000 AND 900000). Which is a pretty close call (50 vs. 32), so +# the planner could get it wrong with an unlucky set of samples. This +# case happens to work, but others ("b BETWEEN 40 AND 44" for example) +# will fail. # +do_execsql_test 3.0 { + SELECT count(*) FROM t1 WHERE b BETWEEN 50 AND 54; + SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000; + SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000; +} {50 376 32} do_test 3.1 { eqp {SELECT * FROM t1 WHERE b BETWEEN 50 AND 54 AND c BETWEEN 0 AND 100000} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?) (~6 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}} do_test 3.2 { eqp {SELECT * FROM t1 WHERE b BETWEEN 50 AND 54 AND c BETWEEN 800000 AND 900000} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?) (~4 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}} do_test 3.3 { eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 0 AND 100000} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~63 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 3.4 { eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 800000 AND 900000} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}} finish_test diff --git a/test/analyze9.test b/test/analyze9.test new file mode 100644 index 0000000..0d72658 --- /dev/null +++ b/test/analyze9.test @@ -0,0 +1,1091 @@ +# 2013 August 3 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file contains automated tests used to verify that the sqlite_stat4 +# functionality is working. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix analyze9 + +ifcapable !stat4 { + finish_test + return +} + +proc s {blob} { + set ret "" + binary scan $blob c* bytes + foreach b $bytes { + set t [binary format c $b] + if {[string is print $t]} { + append ret $t + } else { + append ret . + } + } + return $ret +} +db function s s + +do_execsql_test 1.0 { + CREATE TABLE t1(a TEXT, b TEXT); + INSERT INTO t1 VALUES('(0)', '(0)'); + INSERT INTO t1 VALUES('(1)', '(1)'); + INSERT INTO t1 VALUES('(2)', '(2)'); + INSERT INTO t1 VALUES('(3)', '(3)'); + INSERT INTO t1 VALUES('(4)', '(4)'); + CREATE INDEX i1 ON t1(a, b); +} {} + + +do_execsql_test 1.1 { + ANALYZE; +} {} + +do_execsql_test 1.2 { + SELECT tbl,idx,nEq,nLt,nDLt,test_decode(sample) FROM sqlite_stat4; +} { + t1 i1 {1 1 1} {0 0 0} {0 0 0} {(0) (0) 1} + t1 i1 {1 1 1} {1 1 1} {1 1 1} {(1) (1) 2} + t1 i1 {1 1 1} {2 2 2} {2 2 2} {(2) (2) 3} + t1 i1 {1 1 1} {3 3 3} {3 3 3} {(3) (3) 4} + t1 i1 {1 1 1} {4 4 4} {4 4 4} {(4) (4) 5} +} + +if {[permutation] != "utf16"} { + do_execsql_test 1.3 { + SELECT tbl,idx,nEq,nLt,nDLt,s(sample) FROM sqlite_stat4; + } { + t1 i1 {1 1 1} {0 0 0} {0 0 0} ....(0)(0) + t1 i1 {1 1 1} {1 1 1} {1 1 1} ....(1)(1). + t1 i1 {1 1 1} {2 2 2} {2 2 2} ....(2)(2). + t1 i1 {1 1 1} {3 3 3} {3 3 3} ....(3)(3). + t1 i1 {1 1 1} {4 4 4} {4 4 4} ....(4)(4). + } +} + + +#------------------------------------------------------------------------- +# This is really just to test SQL user function "test_decode". +# +reset_db +do_execsql_test 2.1 { + CREATE TABLE t1(a, b, c); + INSERT INTO t1 VALUES('some text', 14, NULL); + INSERT INTO t1 VALUES(22.0, NULL, x'656667'); + CREATE INDEX i1 ON t1(a, b, c); + ANALYZE; + SELECT test_decode(sample) FROM sqlite_stat4; +} { + {22.0 NULL x'656667' 2} + {{some text} 14 NULL 1} +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 3.1 { + CREATE TABLE t2(a, b); + CREATE INDEX i2 ON t2(a, b); + BEGIN; +} + +do_test 3.2 { + for {set i 0} {$i < 1000} {incr i} { + set a [expr $i / 10] + set b [expr int(rand() * 15.0)] + execsql { INSERT INTO t2 VALUES($a, $b) } + } + execsql COMMIT +} {} + +db func lindex lindex + +# Each value of "a" occurs exactly 10 times in the table. +# +do_execsql_test 3.3.1 { + SELECT count(*) FROM t2 GROUP BY a; +} [lrange [string repeat "10 " 100] 0 99] + +# The first element in the "nEq" list of all samples should therefore be 10. +# +do_execsql_test 3.3.2 { + ANALYZE; + SELECT lindex(nEq, 0) FROM sqlite_stat4; +} [lrange [string repeat "10 " 100] 0 23] + +#------------------------------------------------------------------------- +# +do_execsql_test 3.4 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + INSERT INTO t1 VALUES(1, 1, 'one-a'); + INSERT INTO t1 VALUES(11, 1, 'one-b'); + INSERT INTO t1 VALUES(21, 1, 'one-c'); + INSERT INTO t1 VALUES(31, 1, 'one-d'); + INSERT INTO t1 VALUES(41, 1, 'one-e'); + INSERT INTO t1 VALUES(51, 1, 'one-f'); + INSERT INTO t1 VALUES(61, 1, 'one-g'); + INSERT INTO t1 VALUES(71, 1, 'one-h'); + INSERT INTO t1 VALUES(81, 1, 'one-i'); + INSERT INTO t1 VALUES(91, 1, 'one-j'); + INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1; + INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; + INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; + INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; + INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; + CREATE INDEX t1b ON t1(b); + ANALYZE; + SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60; +} {three-d three-e three-f} + + +#------------------------------------------------------------------------- +# These tests verify that the sample selection for stat4 appears to be +# working as designed. +# + +reset_db +db func lindex lindex +db func lrange lrange + +do_execsql_test 4.0 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a, b, c); + CREATE INDEX i1 ON t1(c, b, a); +} + + +proc insert_filler_rows_n {iStart args} { + set A(-ncopy) 1 + set A(-nval) 1 + + foreach {k v} $args { + if {[info exists A($k)]==0} { error "no such option: $k" } + set A($k) $v + } + if {[llength $args] % 2} { + error "option requires an argument: [lindex $args end]" + } + + for {set i 0} {$i < $A(-nval)} {incr i} { + set iVal [expr $iStart+$i] + for {set j 0} {$j < $A(-ncopy)} {incr j} { + execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) } + } + } +} + +do_test 4.1 { + execsql { BEGIN } + insert_filler_rows_n 0 -ncopy 10 -nval 19 + insert_filler_rows_n 20 -ncopy 1 -nval 100 + + execsql { + INSERT INTO t1(c, b, a) VALUES(200, 1, 'a'); + INSERT INTO t1(c, b, a) VALUES(200, 1, 'b'); + INSERT INTO t1(c, b, a) VALUES(200, 1, 'c'); + + INSERT INTO t1(c, b, a) VALUES(200, 2, 'e'); + INSERT INTO t1(c, b, a) VALUES(200, 2, 'f'); + + INSERT INTO t1(c, b, a) VALUES(201, 3, 'g'); + INSERT INTO t1(c, b, a) VALUES(201, 4, 'h'); + + ANALYZE; + SELECT count(*) FROM sqlite_stat4; + SELECT count(*) FROM t1; + } +} {24 297} + +do_execsql_test 4.2 { + SELECT + neq, + lrange(nlt, 0, 2), + lrange(ndlt, 0, 2), + lrange(test_decode(sample), 0, 2) + FROM sqlite_stat4 + ORDER BY rowid LIMIT 16; +} { + {10 10 10 1} {0 0 0} {0 0 0} {0 0 0} + {10 10 10 1} {10 10 10} {1 1 1} {1 1 1} + {10 10 10 1} {20 20 20} {2 2 2} {2 2 2} + {10 10 10 1} {30 30 30} {3 3 3} {3 3 3} + {10 10 10 1} {40 40 40} {4 4 4} {4 4 4} + {10 10 10 1} {50 50 50} {5 5 5} {5 5 5} + {10 10 10 1} {60 60 60} {6 6 6} {6 6 6} + {10 10 10 1} {70 70 70} {7 7 7} {7 7 7} + {10 10 10 1} {80 80 80} {8 8 8} {8 8 8} + {10 10 10 1} {90 90 90} {9 9 9} {9 9 9} + {10 10 10 1} {100 100 100} {10 10 10} {10 10 10} + {10 10 10 1} {110 110 110} {11 11 11} {11 11 11} + {10 10 10 1} {120 120 120} {12 12 12} {12 12 12} + {10 10 10 1} {130 130 130} {13 13 13} {13 13 13} + {10 10 10 1} {140 140 140} {14 14 14} {14 14 14} + {10 10 10 1} {150 150 150} {15 15 15} {15 15 15} +} + +do_execsql_test 4.3 { + SELECT + neq, + lrange(nlt, 0, 2), + lrange(ndlt, 0, 2), + lrange(test_decode(sample), 0, 1) + FROM sqlite_stat4 + ORDER BY rowid DESC LIMIT 2; +} { + {2 1 1 1} {295 296 296} {120 122 125} {201 4} + {5 3 1 1} {290 290 290} {119 119 119} {200 1} +} + +do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120 +do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119 + +# Check that the perioidic samples are present. +do_execsql_test 4.6 { + SELECT count(*) FROM sqlite_stat4 + WHERE lindex(test_decode(sample), 3) IN + ('34', '68', '102', '136', '170', '204', '238', '272') +} {8} + +reset_db +do_test 4.7 { + execsql { + BEGIN; + CREATE TABLE t1(o,t INTEGER PRIMARY KEY); + CREATE INDEX i1 ON t1(o); + } + for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} { + execsql { INSERT INTO t1 VALUES('x', $i) } + } + execsql { + COMMIT; + ANALYZE; + SELECT count(*) FROM sqlite_stat4; + } +} {8} +do_execsql_test 4.8 { + SELECT test_decode(sample) FROM sqlite_stat4; +} { + {x 211} {x 423} {x 635} {x 847} + {x 1590} {x 3710} {x 5830} {x 7950} +} + + +#------------------------------------------------------------------------- +# The following would cause a crash at one point. +# +reset_db +do_execsql_test 5.1 { + PRAGMA encoding = 'utf-16'; + CREATE TABLE t0(v); + ANALYZE; +} + +#------------------------------------------------------------------------- +# This was also crashing (corrupt sqlite_stat4 table). +# +reset_db +do_execsql_test 6.1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a); + CREATE INDEX i2 ON t1(b); + INSERT INTO t1 VALUES(1, 1); + INSERT INTO t1 VALUES(2, 2); + INSERT INTO t1 VALUES(3, 3); + INSERT INTO t1 VALUES(4, 4); + INSERT INTO t1 VALUES(5, 5); + ANALYZE; + PRAGMA writable_schema = 1; + CREATE TEMP TABLE x1 AS + SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat4 + ORDER BY (rowid%5), rowid; + DELETE FROM sqlite_stat4; + INSERT INTO sqlite_stat4 SELECT * FROM x1; + PRAGMA writable_schema = 0; + ANALYZE sqlite_master; +} +do_execsql_test 6.2 { + SELECT * FROM t1 WHERE a = 'abc'; +} + +#------------------------------------------------------------------------- +# The following tests experiment with adding corrupted records to the +# 'sample' column of the sqlite_stat4 table. +# +reset_db +sqlite3_db_config_lookaside db 0 0 0 + +database_may_be_corrupt +do_execsql_test 7.1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); + INSERT INTO t1 VALUES(1, 1); + INSERT INTO t1 VALUES(2, 2); + INSERT INTO t1 VALUES(3, 3); + INSERT INTO t1 VALUES(4, 4); + INSERT INTO t1 VALUES(5, 5); + ANALYZE; + UPDATE sqlite_stat4 SET sample = X'' WHERE rowid = 1; + ANALYZE sqlite_master; +} + +do_execsql_test 7.2 { + UPDATE sqlite_stat4 SET sample = X'FFFF'; + ANALYZE sqlite_master; + SELECT * FROM t1 WHERE a = 1; +} {1 1} + +do_execsql_test 7.3 { + ANALYZE; + UPDATE sqlite_stat4 SET neq = '0 0 0'; + ANALYZE sqlite_master; + SELECT * FROM t1 WHERE a = 1; +} {1 1} + +do_execsql_test 7.4 { + ANALYZE; + UPDATE sqlite_stat4 SET ndlt = '0 0 0'; + ANALYZE sqlite_master; + SELECT * FROM t1 WHERE a = 3; +} {3 3} + +do_execsql_test 7.5 { + ANALYZE; + UPDATE sqlite_stat4 SET nlt = '0 0 0'; + ANALYZE sqlite_master; + SELECT * FROM t1 WHERE a = 5; +} {5 5} + +database_never_corrupt + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 8.1 { + CREATE TABLE t1(x TEXT); + CREATE INDEX i1 ON t1(x); + INSERT INTO t1 VALUES('1'); + INSERT INTO t1 VALUES('2'); + INSERT INTO t1 VALUES('3'); + INSERT INTO t1 VALUES('4'); + ANALYZE; +} +do_execsql_test 8.2 { + SELECT * FROM t1 WHERE x = 3; +} {3} + +#------------------------------------------------------------------------- +# Check that the bug fixed by [91733bc485] really is fixed. +# +reset_db +do_execsql_test 9.1 { + CREATE TABLE t1(a, b, c, d, e); + CREATE INDEX i1 ON t1(a, b, c, d); + CREATE INDEX i2 ON t1(e); +} +do_test 9.2 { + execsql BEGIN; + for {set i 0} {$i < 100} {incr i} { + execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])" + } + for {set i 0} {$i < 20} {incr i} { + execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)" + } + for {set i 102} {$i < 200} {incr i} { + execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])" + } + execsql COMMIT + execsql ANALYZE +} {} + +do_eqp_test 9.3.1 { + SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=101 AND e=5; +} {/t1 USING INDEX i2/} +do_eqp_test 9.3.2 { + SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=99 AND e=5; +} {/t1 USING INDEX i1/} + +set value_d [expr 101] +do_eqp_test 9.4.1 { + SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5 +} {/t1 USING INDEX i2/} +set value_d [expr 99] +do_eqp_test 9.4.2 { + SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5 +} {/t1 USING INDEX i1/} + +#------------------------------------------------------------------------- +# Check that the planner takes stat4 data into account when considering +# "IS NULL" and "IS NOT NULL" constraints. +# +do_execsql_test 10.1.1 { + DROP TABLE IF EXISTS t3; + CREATE TABLE t3(a, b); + CREATE INDEX t3a ON t3(a); + CREATE INDEX t3b ON t3(b); +} +do_test 10.1.2 { + for {set i 1} {$i < 100} {incr i} { + if {$i>90} { set a $i } else { set a NULL } + set b [expr $i % 5] + execsql "INSERT INTO t3 VALUES($a, $b)" + } + execsql ANALYZE +} {} +do_eqp_test 10.1.3 { + SELECT * FROM t3 WHERE a IS NULL AND b = 2 +} {/t3 USING INDEX t3b/} +do_eqp_test 10.1.4 { + SELECT * FROM t3 WHERE a IS NOT NULL AND b = 2 +} {/t3 USING INDEX t3a/} + +do_execsql_test 10.2.1 { + DROP TABLE IF EXISTS t3; + CREATE TABLE t3(x, a, b); + CREATE INDEX t3a ON t3(x, a); + CREATE INDEX t3b ON t3(x, b); +} +do_test 10.2.2 { + for {set i 1} {$i < 100} {incr i} { + if {$i>90} { set a $i } else { set a NULL } + set b [expr $i % 5] + execsql "INSERT INTO t3 VALUES('xyz', $a, $b)" + } + execsql ANALYZE +} {} +do_eqp_test 10.2.3 { + SELECT * FROM t3 WHERE x = 'xyz' AND a IS NULL AND b = 2 +} {/t3 USING INDEX t3b/} +do_eqp_test 10.2.4 { + SELECT * FROM t3 WHERE x = 'xyz' AND a IS NOT NULL AND b = 2 +} {/t3 USING INDEX t3a/} + +#------------------------------------------------------------------------- +# Check that stat4 data is used correctly with non-default collation +# sequences. +# +foreach {tn schema} { + 1 { + CREATE TABLE t4(a COLLATE nocase, b); + CREATE INDEX t4a ON t4(a); + CREATE INDEX t4b ON t4(b); + } + 2 { + CREATE TABLE t4(a, b); + CREATE INDEX t4a ON t4(a COLLATE nocase); + CREATE INDEX t4b ON t4(b); + } +} { + drop_all_tables + do_test 11.$tn.1 { execsql $schema } {} + + do_test 11.$tn.2 { + for {set i 0} {$i < 100} {incr i} { + if { ($i % 10)==0 } { set a ABC } else { set a DEF } + set b [expr $i % 5] + execsql { INSERT INTO t4 VALUES($a, $b) } + } + execsql ANALYZE + } {} + + do_eqp_test 11.$tn.3 { + SELECT * FROM t4 WHERE a = 'def' AND b = 3; + } {/t4 USING INDEX t4b/} + + if {$tn==1} { + set sql "SELECT * FROM t4 WHERE a = 'abc' AND b = 3;" + do_eqp_test 11.$tn.4 $sql {/t4 USING INDEX t4a/} + } else { + + set sql "SELECT * FROM t4 WHERE a = 'abc' COLLATE nocase AND b = 3;" + do_eqp_test 11.$tn.5 $sql {/t4 USING INDEX t4a/} + + set sql "SELECT * FROM t4 WHERE a COLLATE nocase = 'abc' AND b = 3;" + do_eqp_test 11.$tn.6 $sql {/t4 USING INDEX t4a/} + } +} + +foreach {tn schema} { + 1 { + CREATE TABLE t4(x, a COLLATE nocase, b); + CREATE INDEX t4a ON t4(x, a); + CREATE INDEX t4b ON t4(x, b); + } + 2 { + CREATE TABLE t4(x, a, b); + CREATE INDEX t4a ON t4(x, a COLLATE nocase); + CREATE INDEX t4b ON t4(x, b); + } +} { + drop_all_tables + do_test 12.$tn.1 { execsql $schema } {} + + do_test 12.$tn.2 { + for {set i 0} {$i < 100} {incr i} { + if { ($i % 10)==0 } { set a ABC } else { set a DEF } + set b [expr $i % 5] + execsql { INSERT INTO t4 VALUES(X'abcdef', $a, $b) } + } + execsql ANALYZE + } {} + + do_eqp_test 12.$tn.3 { + SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'def' AND b = 3; + } {/t4 USING INDEX t4b/} + + if {$tn==1} { + set sql "SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'abc' AND b = 3;" + do_eqp_test 12.$tn.4 $sql {/t4 USING INDEX t4a/} + } else { + set sql { + SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'abc' COLLATE nocase AND b = 3 + } + do_eqp_test 12.$tn.5 $sql {/t4 USING INDEX t4a/} + set sql { + SELECT * FROM t4 WHERE x=X'abcdef' AND a COLLATE nocase = 'abc' AND b = 3 + } + do_eqp_test 12.$tn.6 $sql {/t4 USING INDEX t4a/} + } +} + +#------------------------------------------------------------------------- +# Check that affinities are taken into account when using stat4 data to +# estimate the number of rows scanned by a rowid constraint. +# +drop_all_tables +do_test 13.1 { + execsql { + CREATE TABLE t1(a, b, c, d); + CREATE INDEX i1 ON t1(a); + CREATE INDEX i2 ON t1(b, c); + } + for {set i 0} {$i<100} {incr i} { + if {$i %2} {set a abc} else {set a def} + execsql { INSERT INTO t1(rowid, a, b, c) VALUES($i, $a, $i, $i) } + } + execsql ANALYZE +} {} +do_eqp_test 13.2.1 { + SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<12 +} {/SEARCH TABLE t1 USING INDEX i1/} +do_eqp_test 13.2.2 { + SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<12 +} {/SEARCH TABLE t1 USING INDEX i1/} +do_eqp_test 13.3.1 { + SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<12 +} {/SEARCH TABLE t1 USING INDEX i2/} +do_eqp_test 13.3.2 { + SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<12 +} {/SEARCH TABLE t1 USING INDEX i2/} + +#------------------------------------------------------------------------- +# Check also that affinities are taken into account when using stat4 data +# to estimate the number of rows scanned by any other constraint on a +# column other than the leftmost. +# +drop_all_tables +do_test 14.1 { + execsql { CREATE TABLE t1(a, b INTEGER, c) } + for {set i 0} {$i<100} {incr i} { + set c [expr $i % 3] + execsql { INSERT INTO t1 VALUES('ott', $i, $c) } + } + execsql { + CREATE INDEX i1 ON t1(a, b); + CREATE INDEX i2 ON t1(c); + ANALYZE; + } +} {} +do_eqp_test 13.2.1 { + SELECT * FROM t1 WHERE a='ott' AND b<10 AND c=1 +} {/SEARCH TABLE t1 USING INDEX i1/} +do_eqp_test 13.2.2 { + SELECT * FROM t1 WHERE a='ott' AND b<'10' AND c=1 +} {/SEARCH TABLE t1 USING INDEX i1/} + +#------------------------------------------------------------------------- +# By default, 16 non-periodic samples are collected for the stat4 table. +# The following tests attempt to verify that the most common keys are +# being collected. +# +proc check_stat4 {tn} { + db eval ANALYZE + db eval {SELECT a, b, c, d FROM t1} { + incr k($a) + incr k([list $a $b]) + incr k([list $a $b $c]) + if { [info exists k([list $a $b $c $d])]==0 } { incr nRow } + incr k([list $a $b $c $d]) + } + + set L [list] + foreach key [array names k] { + lappend L [list $k($key) $key] + } + + set nSample $nRow + if {$nSample>16} {set nSample 16} + + set nThreshold [lindex [lsort -decr -integer -index 0 $L] [expr $nSample-1] 0] + foreach key [array names k] { + if {$k($key)>$nThreshold} { + set expect($key) 1 + } + if {$k($key)==$nThreshold} { + set possible($key) 1 + } + } + + + set nPossible [expr $nSample - [llength [array names expect]]] + + #puts "EXPECT: [array names expect]" + #puts "POSSIBLE($nPossible/[array size possible]): [array names possible]" + #puts "HAVE: [db eval {SELECT test_decode(sample) FROM sqlite_stat4 WHERE idx='i1'}]" + + db eval {SELECT test_decode(sample) AS s FROM sqlite_stat4 WHERE idx='i1'} { + set seen 0 + for {set i 0} {$i<4} {incr i} { + unset -nocomplain expect([lrange $s 0 $i]) + if {[info exists possible([lrange $s 0 $i])]} { + set seen 1 + unset -nocomplain possible([lrange $s 0 $i]) + } + } + if {$seen} {incr nPossible -1} + } + if {$nPossible<0} {set nPossible 0} + + set res [list [llength [array names expect]] $nPossible] + uplevel [list do_test $tn [list set {} $res] {0 0}] +} + +drop_all_tables +do_test 14.1.1 { + execsql { + CREATE TABLE t1(a,b,c,d); + CREATE INDEX i1 ON t1(a,b,c,d); + } + for {set i 0} {$i < 160} {incr i} { + execsql { INSERT INTO t1 VALUES($i,$i,$i,$i) } + if {($i % 10)==0} { execsql { INSERT INTO t1 VALUES($i,$i,$i,$i) } } + } +} {} +check_stat4 14.1.2 + +do_test 14.2.1 { + execsql { DELETE FROM t1 } + for {set i 0} {$i < 1600} {incr i} { + execsql { INSERT INTO t1 VALUES($i/10,$i/17,$i/27,$i/37) } + } +} {} +check_stat4 14.2.2 + +do_test 14.3.1 { + for {set i 0} {$i < 10} {incr i} { + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) } + } +} {} +check_stat4 14.3.2 + +do_test 14.4.1 { + execsql {DELETE FROM t1} + for {set i 1} {$i < 160} {incr i} { + set b [expr $i % 10] + if {$b==0 || $b==2} {set b 1} + execsql { INSERT INTO t1 VALUES($i/10,$b,$i,$i) } + } +} {} +check_stat4 14.4.2 +db func lrange lrange +db func lindex lindex +do_execsql_test 14.4.3 { + SELECT lrange(test_decode(sample), 0, 1) AS s FROM sqlite_stat4 + WHERE lindex(s, 1)=='1' ORDER BY rowid +} { + {0 1} {1 1} {2 1} {3 1} + {4 1} {5 1} {6 1} {7 1} + {8 1} {9 1} {10 1} {11 1} + {12 1} {13 1} {14 1} {15 1} +} + +#------------------------------------------------------------------------- +# Test that nothing untoward happens if the stat4 table contains entries +# for indexes that do not exist. Or NULL values in the idx column. +# Or NULL values in any of the other columns. +# +drop_all_tables +do_execsql_test 15.1 { + CREATE TABLE x1(a, b, UNIQUE(a, b)); + INSERT INTO x1 VALUES(1, 2); + INSERT INTO x1 VALUES(3, 4); + INSERT INTO x1 VALUES(5, 6); + ANALYZE; + INSERT INTO sqlite_stat4 VALUES(NULL, NULL, NULL, NULL, NULL, NULL); +} +db close +sqlite3 db test.db +do_execsql_test 15.2 { SELECT * FROM x1 } {1 2 3 4 5 6} + +do_execsql_test 15.3 { + INSERT INTO sqlite_stat4 VALUES(42, 42, 42, 42, 42, 42); +} +db close +sqlite3 db test.db +do_execsql_test 15.4 { SELECT * FROM x1 } {1 2 3 4 5 6} + +do_execsql_test 15.5 { + UPDATE sqlite_stat1 SET stat = NULL; +} +db close +sqlite3 db test.db +do_execsql_test 15.6 { SELECT * FROM x1 } {1 2 3 4 5 6} + +do_execsql_test 15.7 { + ANALYZE; + UPDATE sqlite_stat1 SET tbl = 'no such tbl'; +} +db close +sqlite3 db test.db +do_execsql_test 15.8 { SELECT * FROM x1 } {1 2 3 4 5 6} + +do_execsql_test 15.9 { + ANALYZE; + UPDATE sqlite_stat4 SET neq = NULL, nlt=NULL, ndlt=NULL; +} +db close +sqlite3 db test.db +do_execsql_test 15.10 { SELECT * FROM x1 } {1 2 3 4 5 6} + +# This is just for coverage.... +do_execsql_test 15.11 { + ANALYZE; + UPDATE sqlite_stat1 SET stat = stat || ' unordered'; +} +db close +sqlite3 db test.db +do_execsql_test 15.12 { SELECT * FROM x1 } {1 2 3 4 5 6} + +#------------------------------------------------------------------------- +# Test that allocations used for sqlite_stat4 samples are included in +# the quantity returned by SQLITE_DBSTATUS_SCHEMA_USED. +# +set one [string repeat x 1000] +set two [string repeat x 2000] +do_test 16.1 { + reset_db + execsql { + CREATE TABLE t1(a, UNIQUE(a)); + INSERT INTO t1 VALUES($one); + ANALYZE; + } + set nByte [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] + + reset_db + execsql { + CREATE TABLE t1(a, UNIQUE(a)); + INSERT INTO t1 VALUES($two); + ANALYZE; + } + set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] + puts -nonewline " (nByte=$nByte nByte2=$nByte2)" + + expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1100} +} {1} + +#------------------------------------------------------------------------- +# Test that stat4 data may be used with partial indexes. +# +do_test 17.1 { + reset_db + execsql { + CREATE TABLE t1(a, b, c, d); + CREATE INDEX i1 ON t1(a, b) WHERE d IS NOT NULL; + INSERT INTO t1 VALUES(-1, -1, -1, NULL); + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + } + + for {set i 0} {$i < 32} {incr i} { + if {$i<8} {set b 0} else { set b $i } + execsql { INSERT INTO t1 VALUES($i%2, $b, $i/2, 'abc') } + } + execsql {ANALYZE main.t1} +} {} + +do_catchsql_test 17.1.2 { + ANALYZE temp.t1; +} {1 {no such table: temp.t1}} + +do_eqp_test 17.2 { + SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=10 AND c=10; +} {/USING INDEX i1/} +do_eqp_test 17.3 { + SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10; +} {/USING INDEX i1/} + +do_execsql_test 17.4 { + CREATE INDEX i2 ON t1(c, d); + ANALYZE main.i2; +} +do_eqp_test 17.5 { + SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=10 AND c=10; +} {/USING INDEX i1/} +do_eqp_test 17.6 { + SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10; +} {/USING INDEX i2/} + +#------------------------------------------------------------------------- +# +do_test 18.1 { + reset_db + execsql { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); + } + for {set i 0} {$i < 9} {incr i} { + execsql { + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + } + } + execsql ANALYZE + execsql { SELECT count(*) FROM sqlite_stat4 } +} {9} + +#------------------------------------------------------------------------- +# For coverage. +# +ifcapable view { + do_test 19.1 { + reset_db + execsql { + CREATE TABLE t1(x, y); + CREATE INDEX i1 ON t1(x, y); + CREATE VIEW v1 AS SELECT * FROM t1; + ANALYZE; + } + } {} +} +ifcapable auth { + proc authproc {op args} { + if {$op == "SQLITE_ANALYZE"} { return "SQLITE_DENY" } + return "SQLITE_OK" + } + do_test 19.2 { + reset_db + db auth authproc + execsql { + CREATE TABLE t1(x, y); + CREATE VIEW v1 AS SELECT * FROM t1; + } + catchsql ANALYZE + } {1 {not authorized}} +} + +#------------------------------------------------------------------------- +# +reset_db +proc r {args} { expr rand() } +db func r r +db func lrange lrange +do_test 20.1 { + execsql { + CREATE TABLE t1(a,b,c,d); + CREATE INDEX i1 ON t1(a,b,c,d); + } + for {set i 0} {$i < 16} {incr i} { + execsql { + INSERT INTO t1 VALUES($i, r(), r(), r()); + INSERT INTO t1 VALUES($i, $i, r(), r()); + INSERT INTO t1 VALUES($i, $i, $i, r()); + INSERT INTO t1 VALUES($i, $i, $i, $i); + INSERT INTO t1 VALUES($i, $i, $i, $i); + INSERT INTO t1 VALUES($i, $i, $i, r()); + INSERT INTO t1 VALUES($i, $i, r(), r()); + INSERT INTO t1 VALUES($i, r(), r(), r()); + } + } +} {} +do_execsql_test 20.2 { ANALYZE } +for {set i 0} {$i<16} {incr i} { + set val "$i $i $i $i" + do_execsql_test 20.3.$i { + SELECT count(*) FROM sqlite_stat4 + WHERE lrange(test_decode(sample), 0, 3)=$val + } {1} +} + +#------------------------------------------------------------------------- +# +reset_db + +do_execsql_test 21.0 { + CREATE TABLE t2(a, b); + CREATE INDEX i2 ON t2(a); +} + +do_test 21.1 { + for {set i 1} {$i < 100} {incr i} { + execsql { + INSERT INTO t2 VALUES(CASE WHEN $i < 80 THEN 'one' ELSE 'two' END, $i) + } + } + execsql ANALYZE +} {} + +# Condition (a='one') matches 80% of the table. (rowid<10) reduces this to +# 10%, but (rowid<50) only reduces it to 50%. So in the first case below +# the index is used. In the second, it is not. +# +do_eqp_test 21.2 { + SELECT * FROM t2 WHERE a='one' AND rowid < 10 +} {/*USING INDEX i2 (a=? AND rowid<?)*/} +do_eqp_test 21.3 { + SELECT * FROM t2 WHERE a='one' AND rowid < 50 +} {/*USING INTEGER PRIMARY KEY*/} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 22.0 { + CREATE TABLE t3(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID; +} +do_execsql_test 22.1 { + WITH r(x) AS ( + SELECT 1 + UNION ALL + SELECT x+1 FROM r WHERE x<=100 + ) + + INSERT INTO t3 SELECT + CASE WHEN (x>45 AND x<96) THEN 'B' ELSE 'A' END, /* Column "a" */ + x, /* Column "b" */ + CASE WHEN (x<51) THEN 'one' ELSE 'two' END, /* Column "c" */ + x /* Column "d" */ + FROM r; + + CREATE INDEX i3 ON t3(c); + CREATE INDEX i4 ON t3(d); + ANALYZE; +} + +# Expression (c='one' AND a='B') matches 5 table rows. But (c='one' AND a=A') +# matches 45. Expression (d<?) matches 20. Neither index is a covering index. +# +# Therefore, with stat4 data, SQLite prefers (c='one' AND a='B') over (d<20), +# and (d<20) over (c='one' AND a='A'). +foreach {tn where res} { + 1 "c='one' AND a='B' AND d < 20" {/*INDEX i3 (c=? AND a=?)*/} + 2 "c='one' AND a='A' AND d < 20" {/*INDEX i4 (d<?)*/} +} { + do_eqp_test 22.2.$tn "SELECT * FROM t3 WHERE $where" $res +} + +proc int_to_char {i} { + set ret "" + set char [list a b c d e f g h i j] + foreach {div} {1000 100 10 1} { + append ret [lindex $char [expr ($i / $div) % 10]] + } + set ret +} +db func int_to_char int_to_char + +do_execsql_test 23.0 { + CREATE TABLE t4( + a COLLATE nocase, b, c, + d, e, f, + PRIMARY KEY(c, b, a) + ) WITHOUT ROWID; + CREATE INDEX i41 ON t4(e); + CREATE INDEX i42 ON t4(f); + + WITH data(a, b, c, d, e, f) AS ( + SELECT int_to_char(0), 'xyz', 'zyx', '*', 0, 0 + UNION ALL + SELECT + int_to_char(f+1), b, c, d, (e+1) % 2, f+1 + FROM data WHERE f<1024 + ) + INSERT INTO t4 SELECT a, b, c, d, e, f FROM data; + ANALYZE; +} {} + +do_eqp_test 23.1 { + SELECT * FROM t4 WHERE + (e=1 AND b='xyz' AND c='zyx' AND a<'AEA') AND f<300 +} { + 0 0 0 {SEARCH TABLE t4 USING INDEX i41 (e=? AND c=? AND b=? AND a<?)} +} +do_eqp_test 23.2 { + SELECT * FROM t4 WHERE + (e=1 AND b='xyz' AND c='zyx' AND a<'JJJ') AND f<300 +} { + 0 0 0 {SEARCH TABLE t4 USING INDEX i42 (f<?)} +} + +do_execsql_test 24.0 { + CREATE TABLE t5(c, d, b, e, a, PRIMARY KEY(a, b, c)) WITHOUT ROWID; + WITH data(a, b, c, d, e) AS ( + SELECT 'z', 'y', 0, 0, 0 + UNION ALL + SELECT + a, CASE WHEN b='y' THEN 'n' ELSE 'y' END, c+1, e/250, e+1 + FROM data + WHERE e<1000 + ) + INSERT INTO t5(a, b, c, d, e) SELECT * FROM data; + CREATE INDEX t5d ON t5(d); + CREATE INDEX t5e ON t5(e); + ANALYZE; +} + +foreach {tn where eqp} { + 1 "d=0 AND a='z' AND b='n' AND e<200" {/*t5d (d=? AND a=? AND b=?)*/} + 2 "d=0 AND a='z' AND b='n' AND e<100" {/*t5e (e<?)*/} + + 3 "d=0 AND e<300" {/*t5d (d=?)*/} + 4 "d=0 AND e<200" {/*t5e (e<?)*/} +} { + do_eqp_test 24.$tn "SeLeCt * FROM t5 WHERE $where" $eqp +} + +finish_test diff --git a/test/analyzeA.test b/test/analyzeA.test new file mode 100644 index 0000000..d9ca2c0 --- /dev/null +++ b/test/analyzeA.test @@ -0,0 +1,167 @@ +# 2013 August 3 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file contains automated tests used to verify that the current build +# (which must be either ENABLE_STAT3 or ENABLE_STAT4) works with both stat3 +# and stat4 data. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix analyzeA + +ifcapable !stat4&&!stat3 { + finish_test + return +} + +# Populate the stat3 table according to the current contents of the db +# +proc populate_stat3 {{bDropTable 1}} { + # Open a second connection on database "test.db" and run ANALYZE. If this + # is an ENABLE_STAT3 build, this is all that is required to create and + # populate the sqlite_stat3 table. + # + sqlite3 db2 test.db + execsql { ANALYZE } + + # Now, if this is an ENABLE_STAT4 build, create and populate the + # sqlite_stat3 table based on the stat4 data gathered by the ANALYZE + # above. Then drop the sqlite_stat4 table. + # + ifcapable stat4 { + db2 func lindex lindex + execsql { + PRAGMA writable_schema = on; + CREATE TABLE sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample); + INSERT INTO sqlite_stat3 + SELECT DISTINCT tbl, idx, + lindex(neq,0), lindex(nlt,0), lindex(ndlt,0), test_extract(sample, 0) + FROM sqlite_stat4; + } db2 + if {$bDropTable} { execsql {DROP TABLE sqlite_stat4} db2 } + execsql { PRAGMA writable_schema = off } + } + + # Modify the database schema cookie to ensure that the other connection + # reloads the schema. + # + execsql { + CREATE TABLE obscure_tbl_nm(x); + DROP TABLE obscure_tbl_nm; + } db2 + db2 close +} + +# Populate the stat4 table according to the current contents of the db +# +proc populate_stat4 {{bDropTable 1}} { + sqlite3 db2 test.db + execsql { ANALYZE } + + ifcapable stat3 { + execsql { + PRAGMA writable_schema = on; + CREATE TABLE sqlite_stat4(tbl,idx,neq,nlt,ndlt,sample); + INSERT INTO sqlite_stat4 + SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample) + FROM sqlite_stat3; + } db2 + if {$bDropTable} { execsql {DROP TABLE sqlite_stat3} db2 } + execsql { PRAGMA writable_schema = off } + } + + # Modify the database schema cookie to ensure that the other connection + # reloads the schema. + # + execsql { + CREATE TABLE obscure_tbl_nm(x); + DROP TABLE obscure_tbl_nm; + } db2 + db2 close +} + +# Populate the stat4 table according to the current contents of the db. +# Leave deceptive data in the stat3 table. This data should be ignored +# in favour of that from the stat4 table. +# +proc populate_both {} { + ifcapable stat4 { populate_stat3 0 } + ifcapable stat3 { populate_stat4 0 } + + sqlite3 db2 test.db + execsql { + PRAGMA writable_schema = on; + UPDATE sqlite_stat3 SET idx = + CASE idx WHEN 't1b' THEN 't1c' ELSE 't1b' + END; + PRAGMA writable_schema = off; + CREATE TABLE obscure_tbl_nm(x); + DROP TABLE obscure_tbl_nm; + } db2 + db2 close +} + +foreach {tn analyze_cmd} { + 1 populate_stat4 + 2 populate_stat3 + 3 populate_both +} { + reset_db + do_test 1.$tn.1 { + execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) } + for {set i 0} {$i < 100} {incr i} { + set c [expr int(pow(1.1,$i)/100)] + set b [expr 125 - int(pow(1.1,99-$i))/100] + execsql {INSERT INTO t1 VALUES($i, $b, $c)} + } + } {} + + execsql { CREATE INDEX t1b ON t1(b) } + execsql { CREATE INDEX t1c ON t1(c) } + $analyze_cmd + + do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1 + do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0 } 49 + do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125 } 49 + do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16 } 1 + + do_eqp_test 1.$tn.2.5 { + SELECT * FROM t1 WHERE b = 31 AND c = 0; + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} + do_eqp_test 1.$tn.2.6 { + SELECT * FROM t1 WHERE b = 125 AND c = 16; + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)}} + + do_execsql_test 1.$tn.3.1 { + SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50 + } {6} + do_execsql_test 1.$tn.3.2 { + SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50 + } {90} + do_execsql_test 1.$tn.3.3 { + SELECT count(*) FROM t1 WHERE b BETWEEN 75 AND 125 + } {90} + do_execsql_test 1.$tn.3.4 { + SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125 + } {6} + + do_eqp_test 1.$tn.3.5 { + SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50 + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}} + + do_eqp_test 1.$tn.3.6 { + SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125 + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}} +} + +finish_test + diff --git a/test/analyzeB.test b/test/analyzeB.test new file mode 100644 index 0000000..2a78c18 --- /dev/null +++ b/test/analyzeB.test @@ -0,0 +1,683 @@ +# 2013 August 3 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file contains automated tests used to verify that the sqlite_stat3 +# functionality is working. The tests in this file are based on a subset +# of the sqlite_stat4 tests in analyze9.test. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix analyzeB + +ifcapable !stat3 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a TEXT, b TEXT); + INSERT INTO t1 VALUES('(0)', '(0)'); + INSERT INTO t1 VALUES('(1)', '(1)'); + INSERT INTO t1 VALUES('(2)', '(2)'); + INSERT INTO t1 VALUES('(3)', '(3)'); + INSERT INTO t1 VALUES('(4)', '(4)'); + CREATE INDEX i1 ON t1(a, b); +} {} + + +do_execsql_test 1.1 { + ANALYZE; +} {} + +do_execsql_test 1.2 { + SELECT tbl,idx,nEq,nLt,nDLt,quote(sample) FROM sqlite_stat3; +} { + t1 i1 1 0 0 '(0)' + t1 i1 1 1 1 '(1)' + t1 i1 1 2 2 '(2)' + t1 i1 1 3 3 '(3)' + t1 i1 1 4 4 '(4)' +} + +if {[permutation] != "utf16"} { + do_execsql_test 1.3 { + SELECT tbl,idx,nEq,nLt,nDLt,quote(sample) FROM sqlite_stat3; + } { + t1 i1 1 0 0 '(0)' + t1 i1 1 1 1 '(1)' + t1 i1 1 2 2 '(2)' + t1 i1 1 3 3 '(3)' + t1 i1 1 4 4 '(4)' + } +} + + +#------------------------------------------------------------------------- +# This is really just to test SQL user function "test_decode". +# +reset_db +do_execsql_test 2.1 { + CREATE TABLE t1(a, b, c); + INSERT INTO t1(a) VALUES('some text'); + INSERT INTO t1(a) VALUES(14); + INSERT INTO t1(a) VALUES(NULL); + INSERT INTO t1(a) VALUES(22.0); + INSERT INTO t1(a) VALUES(x'656667'); + CREATE INDEX i1 ON t1(a, b, c); + ANALYZE; + SELECT quote(sample) FROM sqlite_stat3; +} { + NULL 14 22.0 {'some text'} X'656667' +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 3.1 { + CREATE TABLE t2(a, b); + CREATE INDEX i2 ON t2(a, b); + BEGIN; +} + +do_test 3.2 { + for {set i 0} {$i < 1000} {incr i} { + set a [expr $i / 10] + set b [expr int(rand() * 15.0)] + execsql { INSERT INTO t2 VALUES($a, $b) } + } + execsql COMMIT +} {} + +db func lindex lindex + +# Each value of "a" occurs exactly 10 times in the table. +# +do_execsql_test 3.3.1 { + SELECT count(*) FROM t2 GROUP BY a; +} [lrange [string repeat "10 " 100] 0 99] + +# The first element in the "nEq" list of all samples should therefore be 10. +# +do_execsql_test 3.3.2 { + ANALYZE; + SELECT nEq FROM sqlite_stat3; +} [lrange [string repeat "10 " 100] 0 23] + +#------------------------------------------------------------------------- +# +do_execsql_test 3.4 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + INSERT INTO t1 VALUES(1, 1, 'one-a'); + INSERT INTO t1 VALUES(11, 1, 'one-b'); + INSERT INTO t1 VALUES(21, 1, 'one-c'); + INSERT INTO t1 VALUES(31, 1, 'one-d'); + INSERT INTO t1 VALUES(41, 1, 'one-e'); + INSERT INTO t1 VALUES(51, 1, 'one-f'); + INSERT INTO t1 VALUES(61, 1, 'one-g'); + INSERT INTO t1 VALUES(71, 1, 'one-h'); + INSERT INTO t1 VALUES(81, 1, 'one-i'); + INSERT INTO t1 VALUES(91, 1, 'one-j'); + INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1; + INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; + INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; + INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; + INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; + CREATE INDEX t1b ON t1(b); + ANALYZE; + SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60; +} {three-d three-e three-f} + + +#------------------------------------------------------------------------- +# These tests verify that the sample selection for stat3 appears to be +# working as designed. +# + +reset_db +db func lindex lindex +db func lrange lrange + +do_execsql_test 4.0 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a, b, c); + CREATE INDEX i1 ON t1(c, b, a); +} + + +proc insert_filler_rows_n {iStart args} { + set A(-ncopy) 1 + set A(-nval) 1 + + foreach {k v} $args { + if {[info exists A($k)]==0} { error "no such option: $k" } + set A($k) $v + } + if {[llength $args] % 2} { + error "option requires an argument: [lindex $args end]" + } + + for {set i 0} {$i < $A(-nval)} {incr i} { + set iVal [expr $iStart+$i] + for {set j 0} {$j < $A(-ncopy)} {incr j} { + execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) } + } + } +} + +do_test 4.1 { + execsql { BEGIN } + insert_filler_rows_n 0 -ncopy 10 -nval 19 + insert_filler_rows_n 20 -ncopy 1 -nval 100 + + execsql { + INSERT INTO t1(c, b, a) VALUES(200, 1, 'a'); + INSERT INTO t1(c, b, a) VALUES(200, 1, 'b'); + INSERT INTO t1(c, b, a) VALUES(200, 1, 'c'); + + INSERT INTO t1(c, b, a) VALUES(200, 2, 'e'); + INSERT INTO t1(c, b, a) VALUES(200, 2, 'f'); + + INSERT INTO t1(c, b, a) VALUES(201, 3, 'g'); + INSERT INTO t1(c, b, a) VALUES(201, 4, 'h'); + + ANALYZE; + SELECT count(*) FROM sqlite_stat3; + SELECT count(*) FROM t1; + } +} {24 297} + +do_execsql_test 4.2 { + SELECT neq, nlt, ndlt, sample FROM sqlite_stat3 ORDER BY rowid LIMIT 16; +} { + 10 0 0 0 + 10 10 1 1 + 10 20 2 2 + 10 30 3 3 + 10 40 4 4 + 10 50 5 5 + 10 60 6 6 + 10 70 7 7 + 10 80 8 8 + 10 90 9 9 + 10 100 10 10 + 10 110 11 11 + 10 120 12 12 + 10 130 13 13 + 10 140 14 14 + 10 150 15 15 +} + +do_execsql_test 4.3 { + SELECT neq, nlt, ndlt, sample FROM sqlite_stat3 + ORDER BY rowid DESC LIMIT 2; +} { + 2 295 120 201 + 5 290 119 200 +} + +do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120 +do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119 + +reset_db +do_test 4.7 { + execsql { + BEGIN; + CREATE TABLE t1(o,t INTEGER PRIMARY KEY); + CREATE INDEX i1 ON t1(o); + } + for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} { + execsql { INSERT INTO t1 VALUES('x', $i) } + } + execsql { + COMMIT; + ANALYZE; + SELECT count(*) FROM sqlite_stat3; + } +} {1} +do_execsql_test 4.8 { + SELECT sample FROM sqlite_stat3; +} {x} + + +#------------------------------------------------------------------------- +# The following would cause a crash at one point. +# +reset_db +do_execsql_test 5.1 { + PRAGMA encoding = 'utf-16'; + CREATE TABLE t0(v); + ANALYZE; +} + +#------------------------------------------------------------------------- +# This was also crashing (corrupt sqlite_stat3 table). +# +reset_db +do_execsql_test 6.1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a); + CREATE INDEX i2 ON t1(b); + INSERT INTO t1 VALUES(1, 1); + INSERT INTO t1 VALUES(2, 2); + INSERT INTO t1 VALUES(3, 3); + INSERT INTO t1 VALUES(4, 4); + INSERT INTO t1 VALUES(5, 5); + ANALYZE; + PRAGMA writable_schema = 1; + CREATE TEMP TABLE x1 AS + SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3 + ORDER BY (rowid%5), rowid; + DELETE FROM sqlite_stat3; + INSERT INTO sqlite_stat3 SELECT * FROM x1; + PRAGMA writable_schema = 0; + ANALYZE sqlite_master; +} +do_execsql_test 6.2 { + SELECT * FROM t1 WHERE a = 'abc'; +} + +#------------------------------------------------------------------------- +# The following tests experiment with adding corrupted records to the +# 'sample' column of the sqlite_stat3 table. +# +reset_db +sqlite3_db_config_lookaside db 0 0 0 + +do_execsql_test 7.1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); + INSERT INTO t1 VALUES(1, 1); + INSERT INTO t1 VALUES(2, 2); + INSERT INTO t1 VALUES(3, 3); + INSERT INTO t1 VALUES(4, 4); + INSERT INTO t1 VALUES(5, 5); + ANALYZE; + UPDATE sqlite_stat3 SET sample = X'' WHERE rowid = 1; + ANALYZE sqlite_master; +} + +do_execsql_test 7.2 { + UPDATE sqlite_stat3 SET sample = X'FFFF'; + ANALYZE sqlite_master; + SELECT * FROM t1 WHERE a = 1; +} {1 1} + +do_execsql_test 7.3 { + ANALYZE; + UPDATE sqlite_stat3 SET neq = '0 0 0'; + ANALYZE sqlite_master; + SELECT * FROM t1 WHERE a = 1; +} {1 1} + +do_execsql_test 7.4 { + ANALYZE; + UPDATE sqlite_stat3 SET ndlt = '0 0 0'; + ANALYZE sqlite_master; + SELECT * FROM t1 WHERE a = 3; +} {3 3} + +do_execsql_test 7.5 { + ANALYZE; + UPDATE sqlite_stat3 SET nlt = '0 0 0'; + ANALYZE sqlite_master; + SELECT * FROM t1 WHERE a = 5; +} {5 5} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 8.1 { + CREATE TABLE t1(x TEXT); + CREATE INDEX i1 ON t1(x); + INSERT INTO t1 VALUES('1'); + INSERT INTO t1 VALUES('2'); + INSERT INTO t1 VALUES('3'); + INSERT INTO t1 VALUES('4'); + ANALYZE; +} +do_execsql_test 8.2 { + SELECT * FROM t1 WHERE x = 3; +} {3} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 9.1 { + CREATE TABLE t1(a, b, c, d, e); + CREATE INDEX i1 ON t1(a, b, c, d); + CREATE INDEX i2 ON t1(e); +} +do_test 9.2 { + execsql BEGIN; + for {set i 0} {$i < 100} {incr i} { + execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])" + } + for {set i 0} {$i < 20} {incr i} { + execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)" + } + for {set i 102} {$i < 200} {incr i} { + execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])" + } + execsql COMMIT + execsql ANALYZE +} {} + +do_eqp_test 9.3.1 { + SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=101 AND e=5; +} {/t1 USING INDEX i1/} +do_eqp_test 9.3.2 { + SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=99 AND e=5; +} {/t1 USING INDEX i1/} + +set value_d [expr 101] +do_eqp_test 9.4.1 { + SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5 +} {/t1 USING INDEX i1/} +set value_d [expr 99] +do_eqp_test 9.4.2 { + SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5 +} {/t1 USING INDEX i1/} + +#------------------------------------------------------------------------- +# Check that the planner takes stat3 data into account when considering +# "IS NULL" and "IS NOT NULL" constraints. +# +do_execsql_test 10.1.1 { + DROP TABLE IF EXISTS t3; + CREATE TABLE t3(a, b); + CREATE INDEX t3a ON t3(a); + CREATE INDEX t3b ON t3(b); +} +do_test 10.1.2 { + for {set i 1} {$i < 100} {incr i} { + if {$i>90} { set a $i } else { set a NULL } + set b [expr $i % 5] + execsql "INSERT INTO t3 VALUES($a, $b)" + } + execsql ANALYZE +} {} +do_eqp_test 10.1.3 { + SELECT * FROM t3 WHERE a IS NULL AND b = 2 +} {/t3 USING INDEX t3b/} +do_eqp_test 10.1.4 { + SELECT * FROM t3 WHERE a IS NOT NULL AND b = 2 +} {/t3 USING INDEX t3a/} + +#------------------------------------------------------------------------- +# Check that stat3 data is used correctly with non-default collation +# sequences. +# +foreach {tn schema} { + 1 { + CREATE TABLE t4(a COLLATE nocase, b); + CREATE INDEX t4a ON t4(a); + CREATE INDEX t4b ON t4(b); + } + 2 { + CREATE TABLE t4(a, b); + CREATE INDEX t4a ON t4(a COLLATE nocase); + CREATE INDEX t4b ON t4(b); + } +} { + drop_all_tables + do_test 11.$tn.1 { execsql $schema } {} + + do_test 11.$tn.2 { + for {set i 0} {$i < 100} {incr i} { + if { ($i % 10)==0 } { set a ABC } else { set a DEF } + set b [expr $i % 5] + execsql { INSERT INTO t4 VALUES($a, $b) } + } + execsql ANALYZE + } {} + + do_eqp_test 11.$tn.3 { + SELECT * FROM t4 WHERE a = 'def' AND b = 3; + } {/t4 USING INDEX t4b/} + + if {$tn==1} { + set sql "SELECT * FROM t4 WHERE a = 'abc' AND b = 3;" + do_eqp_test 11.$tn.4 $sql {/t4 USING INDEX t4a/} + } else { + + set sql "SELECT * FROM t4 WHERE a = 'abc' COLLATE nocase AND b = 3;" + do_eqp_test 11.$tn.5 $sql {/t4 USING INDEX t4a/} + + set sql "SELECT * FROM t4 WHERE a COLLATE nocase = 'abc' AND b = 3;" + do_eqp_test 11.$tn.6 $sql {/t4 USING INDEX t4a/} + } +} + +#------------------------------------------------------------------------- +# Test that nothing untoward happens if the stat3 table contains entries +# for indexes that do not exist. Or NULL values in the idx column. +# Or NULL values in any of the other columns. +# +drop_all_tables +do_execsql_test 15.1 { + CREATE TABLE x1(a, b, UNIQUE(a, b)); + INSERT INTO x1 VALUES(1, 2); + INSERT INTO x1 VALUES(3, 4); + INSERT INTO x1 VALUES(5, 6); + ANALYZE; + INSERT INTO sqlite_stat3 VALUES(NULL, NULL, NULL, NULL, NULL, NULL); +} +db close +sqlite3 db test.db +do_execsql_test 15.2 { SELECT * FROM x1 } {1 2 3 4 5 6} + +do_execsql_test 15.3 { + INSERT INTO sqlite_stat3 VALUES(42, 42, 42, 42, 42, 42); +} +db close +sqlite3 db test.db +do_execsql_test 15.4 { SELECT * FROM x1 } {1 2 3 4 5 6} + +do_execsql_test 15.5 { + UPDATE sqlite_stat1 SET stat = NULL; +} +db close +sqlite3 db test.db +do_execsql_test 15.6 { SELECT * FROM x1 } {1 2 3 4 5 6} + +do_execsql_test 15.7 { + ANALYZE; + UPDATE sqlite_stat1 SET tbl = 'no such tbl'; +} +db close +sqlite3 db test.db +do_execsql_test 15.8 { SELECT * FROM x1 } {1 2 3 4 5 6} + +do_execsql_test 15.9 { + ANALYZE; + UPDATE sqlite_stat3 SET neq = NULL, nlt=NULL, ndlt=NULL; +} +db close +sqlite3 db test.db +do_execsql_test 15.10 { SELECT * FROM x1 } {1 2 3 4 5 6} + +# This is just for coverage.... +do_execsql_test 15.11 { + ANALYZE; + UPDATE sqlite_stat1 SET stat = stat || ' unordered'; +} +db close +sqlite3 db test.db +do_execsql_test 15.12 { SELECT * FROM x1 } {1 2 3 4 5 6} + +#------------------------------------------------------------------------- +# Test that allocations used for sqlite_stat3 samples are included in +# the quantity returned by SQLITE_DBSTATUS_SCHEMA_USED. +# +set one [string repeat x 1000] +set two [string repeat x 2000] +do_test 16.1 { + reset_db + execsql { + CREATE TABLE t1(a, UNIQUE(a)); + INSERT INTO t1 VALUES($one); + ANALYZE; + } + set nByte [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] + + reset_db + execsql { + CREATE TABLE t1(a, UNIQUE(a)); + INSERT INTO t1 VALUES($two); + ANALYZE; + } + set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] + + expr {$nByte2 > $nByte+950 && $nByte2 < $nByte+1050} +} {1} + +#------------------------------------------------------------------------- +# Test that stat3 data may be used with partial indexes. +# +do_test 17.1 { + reset_db + execsql { + CREATE TABLE t1(a, b, c, d); + CREATE INDEX i1 ON t1(a, b) WHERE d IS NOT NULL; + INSERT INTO t1 VALUES(-1, -1, -1, NULL); + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; + } + + for {set i 0} {$i < 32} {incr i} { + execsql { INSERT INTO t1 VALUES($i%2, $b, $i/2, 'abc') } + } + execsql {ANALYZE main.t1} +} {} + +do_catchsql_test 17.1.2 { + ANALYZE temp.t1; +} {1 {no such table: temp.t1}} + +do_eqp_test 17.2 { + SELECT * FROM t1 WHERE d IS NOT NULL AND a=0; +} {/USING INDEX i1/} +do_eqp_test 17.3 { + SELECT * FROM t1 WHERE d IS NOT NULL AND a=0; +} {/USING INDEX i1/} + +do_execsql_test 17.4 { + CREATE INDEX i2 ON t1(c) WHERE d IS NOT NULL; + ANALYZE main.i2; +} +do_eqp_test 17.5 { + SELECT * FROM t1 WHERE d IS NOT NULL AND a=0; +} {/USING INDEX i1/} +do_eqp_test 17.6 { + SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10; +} {/USING INDEX i2/} + +#------------------------------------------------------------------------- +# +do_test 18.1 { + reset_db + execsql { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); + } + for {set i 0} {$i < 9} {incr i} { + execsql { + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + INSERT INTO t1 VALUES($i, 0); + } + } + execsql ANALYZE + execsql { SELECT count(*) FROM sqlite_stat3 } +} {9} + +#------------------------------------------------------------------------- +# For coverage. +# +ifcapable view { + do_test 19.1 { + reset_db + execsql { + CREATE TABLE t1(x, y); + CREATE INDEX i1 ON t1(x, y); + CREATE VIEW v1 AS SELECT * FROM t1; + ANALYZE; + } + } {} +} +ifcapable auth { + proc authproc {op args} { + if {$op == "SQLITE_ANALYZE"} { return "SQLITE_DENY" } + return "SQLITE_OK" + } + do_test 19.2 { + reset_db + db auth authproc + execsql { + CREATE TABLE t1(x, y); + CREATE VIEW v1 AS SELECT * FROM t1; + } + catchsql ANALYZE + } {1 {not authorized}} +} + +#------------------------------------------------------------------------- +# +reset_db +proc r {args} { expr rand() } +db func r r +db func lrange lrange +do_test 20.1 { + execsql { + CREATE TABLE t1(a,b,c,d); + CREATE INDEX i1 ON t1(a,b,c,d); + } + for {set i 0} {$i < 16} {incr i} { + execsql { + INSERT INTO t1 VALUES($i, r(), r(), r()); + INSERT INTO t1 VALUES($i, $i, r(), r()); + INSERT INTO t1 VALUES($i, $i, $i, r()); + INSERT INTO t1 VALUES($i, $i, $i, $i); + INSERT INTO t1 VALUES($i, $i, $i, $i); + INSERT INTO t1 VALUES($i, $i, $i, r()); + INSERT INTO t1 VALUES($i, $i, r(), r()); + INSERT INTO t1 VALUES($i, r(), r(), r()); + } + } +} {} +do_execsql_test 20.2 { ANALYZE } +for {set i 0} {$i<16} {incr i} { + set val $i + do_execsql_test 20.3.$i { + SELECT count(*) FROM sqlite_stat3 WHERE sample=$val + } {1} +} + +finish_test + diff --git a/test/analyzeC.test b/test/analyzeC.test new file mode 100644 index 0000000..02faa9c --- /dev/null +++ b/test/analyzeC.test @@ -0,0 +1,167 @@ +# 2014-07-22 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file contains automated tests used to verify that the text terms +# at the end of sqlite_stat1.stat are processed correctly. +# +# (1) "unordered" means that the index cannot be used for ORDER BY +# or for range queries +# +# (2) "sz=NNN" sets the relative size of the index entries +# +# (3) All other fields are silently ignored +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix analyzeC + +# Baseline case. Range queries work OK. Indexes can be used for +# ORDER BY. +# +do_execsql_test 1.0 { + CREATE TABLE t1(a,b,c); + INSERT INTO t1(a,b,c) + VALUES(1,2,3),(7,8,9),(4,5,6),(10,11,12),(4,8,12),(1,11,111); + CREATE INDEX t1a ON t1(a); + CREATE INDEX t1b ON t1(b); + ANALYZE; + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) + VALUES('t1','t1a','12345 2'),('t1','t1b','12345 4'); + ANALYZE sqlite_master; + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {4 5 6 # 7 8 9 # 4 8 12 #} +do_execsql_test 1.1 { + EXPLAIN QUERY PLAN + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {/.* USING INDEX t1a .a>. AND a<...*/} +do_execsql_test 1.2 { + SELECT c FROM t1 ORDER BY a; +} {3 111 6 12 9 12} +do_execsql_test 1.3 { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {/.*SCAN TABLE t1 USING INDEX t1a.*/} +do_execsql_test 1.3x { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {~/.*B-TREE FOR ORDER BY.*/} + +# Now mark the t1a index as "unordered". Range queries and ORDER BY no +# longer use the index, but equality queries do. +# +do_execsql_test 2.0 { + UPDATE sqlite_stat1 SET stat='12345 2 unordered' WHERE idx='t1a'; + ANALYZE sqlite_master; + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {4 5 6 # 7 8 9 # 4 8 12 #} +do_execsql_test 2.1 { + EXPLAIN QUERY PLAN + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {~/.*USING INDEX.*/} +do_execsql_test 2.2 { + SELECT c FROM t1 ORDER BY a; +} {3 111 6 12 9 12} +do_execsql_test 2.3 { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {~/.*USING INDEX.*/} +do_execsql_test 2.3x { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {/.*B-TREE FOR ORDER BY.*/} + +# Ignore extraneous text parameters in the sqlite_stat1.stat field. +# +do_execsql_test 3.0 { + UPDATE sqlite_stat1 SET stat='12345 2 whatever=5 unordered xyzzy=11' + WHERE idx='t1a'; + ANALYZE sqlite_master; + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {4 5 6 # 7 8 9 # 4 8 12 #} +do_execsql_test 3.1 { + EXPLAIN QUERY PLAN + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {~/.*USING INDEX.*/} +do_execsql_test 3.2 { + SELECT c FROM t1 ORDER BY a; +} {3 111 6 12 9 12} +do_execsql_test 3.3 { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {~/.*USING INDEX.*/} +do_execsql_test 3.3x { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {/.*B-TREE FOR ORDER BY.*/} + +# The sz=NNN parameter determines which index to scan +# +do_execsql_test 4.0 { + DROP INDEX t1a; + CREATE INDEX t1ab ON t1(a,b); + CREATE INDEX t1ca ON t1(c,a); + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) + VALUES('t1','t1ab','12345 3 2 sz=10'),('t1','t1ca','12345 3 2 sz=20'); + ANALYZE sqlite_master; + SELECT count(a) FROM t1; +} {6} +do_execsql_test 4.1 { + EXPLAIN QUERY PLAN + SELECT count(a) FROM t1; +} {/.*INDEX t1ab.*/} +do_execsql_test 4.2 { + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) + VALUES('t1','t1ab','12345 3 2 sz=20'),('t1','t1ca','12345 3 2 sz=10'); + ANALYZE sqlite_master; + SELECT count(a) FROM t1; +} {6} +do_execsql_test 4.3 { + EXPLAIN QUERY PLAN + SELECT count(a) FROM t1; +} {/.*INDEX t1ca.*/} + + +# The sz=NNN parameter works even if there is other extraneous text +# in the sqlite_stat1.stat column. +# +do_execsql_test 5.0 { + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) + VALUES('t1','t1ab','12345 3 2 x=5 sz=10 y=10'), + ('t1','t1ca','12345 3 2 whatever sz=20 junk'); + ANALYZE sqlite_master; + SELECT count(a) FROM t1; +} {6} +do_execsql_test 5.1 { + EXPLAIN QUERY PLAN + SELECT count(a) FROM t1; +} {/.*INDEX t1ab.*/} +do_execsql_test 5.2 { + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) + VALUES('t1','t1ca','12345 3 2 x=5 sz=10 y=10'), + ('t1','t1ab','12345 3 2 whatever sz=20 junk'); + ANALYZE sqlite_master; + SELECT count(a) FROM t1; +} {6} +do_execsql_test 5.3 { + EXPLAIN QUERY PLAN + SELECT count(a) FROM t1; +} {/.*INDEX t1ca.*/} + + + + +finish_test diff --git a/test/async5.test b/test/async5.test index aa484fc..abac11f 100644 --- a/test/async5.test +++ b/test/async5.test @@ -66,4 +66,3 @@ sqlite3async_control halt never sqlite3async_shutdown set sqlite3async_trace 0 finish_test - diff --git a/test/atof1.test b/test/atof1.test index 76eb427..5c04d02 100644 --- a/test/atof1.test +++ b/test/atof1.test @@ -15,7 +15,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -if {![info exists __GNUC__]} { +if {![info exists __GNUC__] || [regexp arm $tcl_platform(machine)]} { finish_test return } diff --git a/test/attach2.test b/test/attach2.test index db23072..f870568 100644 --- a/test/attach2.test +++ b/test/attach2.test @@ -377,6 +377,9 @@ do_test attach2-6.2 { } } {1 {cannot ATTACH database within transaction}} +# EVIDENCE-OF: R-59740-55581 This statement will fail if SQLite is in +# the middle of a transaction. +# do_test attach2-6.3 { catchsql { DETACH aux; diff --git a/test/attach3.test b/test/attach3.test index f861425..1ac10d9 100644 --- a/test/attach3.test +++ b/test/attach3.test @@ -322,7 +322,6 @@ do_test attach3-12.9 { db_list } {main temp {}} do_test attach3-12.10 { -breakpoint execsql { DETACH ? } diff --git a/test/auth.test b/test/auth.test index fd402b1..43e53ef 100644 --- a/test/auth.test +++ b/test/auth.test @@ -2080,6 +2080,42 @@ ifcapable {altertable} { execsql {DROP TABLE t5} } ;# ifcapable altertable +ifcapable {cte} { + do_test auth-1.310 { + proc auth {code arg1 arg2 arg3 arg4} { + if {$code=="SQLITE_RECURSIVE"} { + return SQLITE_DENY + } + return SQLITE_OK + } + db eval { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,2),(3,4),(5,6); + } + } {} + do_catchsql_test auth-1.311 { + WITH + auth1311(x,y) AS (SELECT a+b, b-a FROM t1) + SELECT * FROM auth1311 ORDER BY x; + } {0 {3 1 7 1 11 1}} + do_catchsql_test auth-1.312 { + WITH RECURSIVE + auth1312(x,y) AS (SELECT a+b, b-a FROM t1) + SELECT x, y FROM auth1312 ORDER BY x; + } {0 {3 1 7 1 11 1}} + do_catchsql_test auth-1.313 { + WITH RECURSIVE + auth1313(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM auth1313 WHERE x<5) + SELECT * FROM t1; + } {0 {1 2 3 4 5 6}} + do_catchsql_test auth-1.314 { + WITH RECURSIVE + auth1314(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM auth1314 WHERE x<5) + SELECT * FROM t1 LEFT JOIN auth1314; + } {1 {not authorized}} +} ;# ifcapable cte + do_test auth-2.1 { proc auth {code arg1 arg2 arg3 arg4} { if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} { @@ -2325,10 +2361,14 @@ ifcapable compound&&subquery { } } } - ifcapable stat3 { - set stat3 "sqlite_stat3 " + ifcapable stat4 { + set stat4 "sqlite_stat4 " } else { - set stat3 "" + ifcapable stat3 { + set stat4 "sqlite_stat3 " + } else { + set stat4 "" + } } do_test auth-5.2 { execsql { @@ -2337,7 +2377,7 @@ ifcapable compound&&subquery { WHERE type='table' ORDER BY name } - } "sqlite_stat1 ${stat3}t1 t2 t3 t4" + } "sqlite_stat1 ${stat4}t1 t2 t3 t4" } # Ticket #3944 diff --git a/test/auth2.test b/test/auth2.test index 9343fd6..65e0591 100644 --- a/test/auth2.test +++ b/test/auth2.test @@ -102,6 +102,7 @@ SQLITE_READ sqlite_master name main {} SQLITE_READ sqlite_master rootpage main {} SQLITE_READ sqlite_master sql main {} SQLITE_READ sqlite_master tbl_name main {} +SQLITE_READ sqlite_master type main {} SQLITE_READ sqlite_master ROWID main {} } do_test auth2-2.2 { @@ -122,6 +123,7 @@ SQLITE_READ sqlite_master name main {} SQLITE_READ sqlite_master rootpage main {} SQLITE_READ sqlite_master sql main {} SQLITE_READ sqlite_master tbl_name main {} +SQLITE_READ sqlite_master type main {} SQLITE_READ sqlite_master ROWID main {} } do_test auth2-2.3 { diff --git a/test/autoinc.test b/test/autoinc.test index 98f6919..2396006 100644 --- a/test/autoinc.test +++ b/test/autoinc.test @@ -216,7 +216,7 @@ do_test autoinc-2.27 { } {t1 1238} do_test autoinc-2.28 { execsql { - UPDATE sqlite_sequence SET seq='12345678901234567890' + UPDATE sqlite_sequence SET seq='-12345678901234567890' WHERE name='t1'; INSERT INTO t1 VALUES(NULL,6); SELECT * FROM t1; diff --git a/test/autoindex1.test b/test/autoindex1.test index 54ff82a..6cb0ab1 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -23,6 +23,14 @@ ifcapable {!autoindex} { return } +# Setup for logging +db close +sqlite3_shutdown +test_sqlite3_log [list lappend ::log] +set ::log [list] +sqlite3 db test.db + + # With automatic index turned off, we do a full scan of the T2 table do_test autoindex1-100 { db eval { @@ -60,6 +68,15 @@ do_test autoindex1-111 { do_test autoindex1-112 { db status autoindex } {7} +do_test autoindex1-113 { + set ::log +} {SQLITE_WARNING_AUTOINDEX {automatic index on t2(c)}} + +db close +sqlite3_shutdown +test_sqlite3_log +sqlite3_initialize +sqlite3 db test.db # The same test as above, but this time the T2 query is a subquery rather # than a join. @@ -78,6 +95,11 @@ do_test autoindex1-202 { do_test autoindex1-210 { db eval { PRAGMA automatic_index=ON; + ANALYZE; + UPDATE sqlite_stat1 SET stat='10000' WHERE tbl='t1'; + -- Table t2 actually contains 8 rows. + UPDATE sqlite_stat1 SET stat='16' WHERE tbl='t2'; + ANALYZE sqlite_master; SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1; } } {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988} @@ -91,9 +113,15 @@ do_test autoindex1-212 { # Modify the second table of the join while the join is in progress # +do_execsql_test autoindex1-299 { + UPDATE sqlite_stat1 SET stat='10000' WHERE tbl='t2'; + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN + SELECT b, d FROM t1 CROSS JOIN t2 ON (c=a); +} {/AUTOMATIC COVERING INDEX/} do_test autoindex1-300 { set r {} - db eval {SELECT b, d FROM t1 JOIN t2 ON (c=a)} { + db eval {SELECT b, d FROM t1 CROSS JOIN t2 ON (c=a)} { lappend r $b $d db eval {UPDATE t2 SET d=d+1} } @@ -143,22 +171,25 @@ do_test autoindex1-401 { do_execsql_test autoindex1-500 { CREATE TABLE t501(a INTEGER PRIMARY KEY, b); CREATE TABLE t502(x INTEGER PRIMARY KEY, y); + INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t501',null,'1000000'); + INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t502',null,'1000'); + ANALYZE sqlite_master; EXPLAIN QUERY PLAN SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=?); } { - 0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) (~25 rows)} + 0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {EXECUTE LIST SUBQUERY 1} - 1 0 0 {SCAN TABLE t502 (~100000 rows)} + 1 0 0 {SCAN TABLE t502} } do_execsql_test autoindex1-501 { EXPLAIN QUERY PLAN SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { - 0 0 0 {SCAN TABLE t501 (~500000 rows)} + 0 0 0 {SCAN TABLE t501} 0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1} - 1 0 0 {SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?) (~7 rows)} + 1 0 0 {SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?)} } do_execsql_test autoindex1-502 { EXPLAIN QUERY PLAN @@ -166,9 +197,9 @@ do_execsql_test autoindex1-502 { WHERE t501.a=123 AND t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { - 0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1} - 1 0 0 {SCAN TABLE t502 (~100000 rows)} + 1 0 0 {SCAN TABLE t502} } @@ -240,12 +271,12 @@ do_execsql_test autoindex1-600 { WHERE y.sheep_no IS NULL ORDER BY x.registering_flock; } { - 1 0 0 {SCAN TABLE sheep AS s (~1000000 rows)} - 1 1 1 {SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?) (~2 rows)} + 1 0 0 {SCAN TABLE sheep AS s} + 1 1 1 {SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?)} 1 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} - 2 0 0 {SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?) (~1 rows)} - 0 0 0 {SCAN TABLE sheep AS x USING INDEX sheep_reg_flock_index (~1000000 rows)} - 0 1 1 {SEARCH SUBQUERY 1 AS y USING AUTOMATIC COVERING INDEX (sheep_no=?) (~8 rows)} + 2 0 0 {SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?)} + 0 0 0 {SCAN TABLE sheep AS x USING INDEX sheep_reg_flock_index} + 0 1 1 {SEARCH SUBQUERY 1 AS y USING AUTOMATIC COVERING INDEX (sheep_no=?)} } @@ -253,7 +284,7 @@ do_execsql_test autoindex1-700 { CREATE TABLE t5(a, b, c); EXPLAIN QUERY PLAN SELECT a FROM t5 WHERE b=10 ORDER BY c; } { - 0 0 0 {SCAN TABLE t5 (~100000 rows)} + 0 0 0 {SCAN TABLE t5} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } diff --git a/test/autoindex2.test b/test/autoindex2.test new file mode 100644 index 0000000..f4da416 --- /dev/null +++ b/test/autoindex2.test @@ -0,0 +1,271 @@ +# 2014-06-17 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# +# This file implements regression tests for SQLite library. The +# focus of this script is testing automatic index creation logic. +# +# This file contains a single real-world test case that was giving +# suboptimal performance because of over-use of automatic indexes. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + + +do_execsql_test autoindex2-100 { + CREATE TABLE t1( + t1_id largeint, + did char(9), + ptime largeint, + exbyte char(4), + pe_id int, + field_id int, + mass float, + param10 float, + param11 float, + exmass float, + deviation float, + trange float, + vstatus int, + commit_status int, + formula char(329), + tier int DEFAULT 2, + ssid int DEFAULT 0, + last_operation largeint DEFAULT 0, + admin_uuid int DEFAULT 0, + previous_value float, + job_id largeint, + last_t1 largeint DEFAULT 0, + data_t1 int, + previous_date largeint DEFAULT 0, + flg8 int DEFAULT 1, + failed_fields char(100) + ); + CREATE INDEX t1x0 on t1 (t1_id); + CREATE INDEX t1x1 on t1 (ptime, vstatus); + CREATE INDEX t1x2 on t1 (did, ssid, ptime, vstatus, exbyte, t1_id); + CREATE INDEX t1x3 on t1 (job_id); + + CREATE TABLE t2( + did char(9), + client_did char(30), + description char(49), + uid int, + tzid int, + privilege int, + param2 int, + type char(30), + subtype char(32), + dparam1 char(7) DEFAULT '', + param5 char(3) DEFAULT '', + notional float DEFAULT 0.000000, + create_time largeint, + sample_time largeint DEFAULT 0, + param6 largeint, + frequency int, + expiration largeint, + uw_status int, + next_sample largeint, + last_sample largeint, + reserve1 char(29) DEFAULT '', + reserve2 char(29) DEFAULT '', + reserve3 char(29) DEFAULT '', + bxcdr char(19) DEFAULT 'XY', + ssid int DEFAULT 1, + last_t1_id largeint, + reserve4 char(29) DEFAULT '', + reserve5 char(29) DEFAULT '', + param12 int DEFAULT 0, + long_did char(100) DEFAULT '', + gr_code int DEFAULT 0, + drx char(100) DEFAULT '', + parent_id char(9) DEFAULT '', + param13 int DEFAULT 0, + position float DEFAULT 1.000000, + client_did3 char(100) DEFAULT '', + client_did4 char(100) DEFAULT '', + dlib_id char(9) DEFAULT '' + ); + CREATE INDEX t2x0 on t2 (did); + CREATE INDEX t2x1 on t2 (client_did); + CREATE INDEX t2x2 on t2 (long_did); + CREATE INDEX t2x3 on t2 (uid); + CREATE INDEX t2x4 on t2 (param2); + CREATE INDEX t2x5 on t2 (type); + CREATE INDEX t2x6 on t2 (subtype); + CREATE INDEX t2x7 on t2 (last_sample); + CREATE INDEX t2x8 on t2 (param6); + CREATE INDEX t2x9 on t2 (frequency); + CREATE INDEX t2x10 on t2 (privilege); + CREATE INDEX t2x11 on t2 (sample_time); + CREATE INDEX t2x12 on t2 (notional); + CREATE INDEX t2x13 on t2 (tzid); + CREATE INDEX t2x14 on t2 (gr_code); + CREATE INDEX t2x15 on t2 (parent_id); + + CREATE TABLE t3( + uid int, + param3 int, + uuid int, + acc_id int, + cust_num int, + numerix_id int, + pfy char(29), + param4 char(29), + param15 int DEFAULT 0, + flg7 int DEFAULT 0, + param21 int DEFAULT 0, + bxcdr char(2) DEFAULT 'PC', + c31 int DEFAULT 0, + c33 int DEFAULT 0, + c35 int DEFAULT 0, + c37 int, + mgr_uuid int, + back_up_uuid int, + priv_mars int DEFAULT 0, + is_qc int DEFAULT 0, + c41 int DEFAULT 0, + deleted int DEFAULT 0, + c47 int DEFAULT 1 + ); + CREATE INDEX t3x0 on t3 (uid); + CREATE INDEX t3x1 on t3 (param3); + CREATE INDEX t3x2 on t3 (uuid); + CREATE INDEX t3x3 on t3 (acc_id); + CREATE INDEX t3x4 on t3 (param4); + CREATE INDEX t3x5 on t3 (pfy); + CREATE INDEX t3x6 on t3 (is_qc); + SELECT count(*) FROM sqlite_master; +} {30} +do_execsql_test autoindex2-110 { + ANALYZE sqlite_master; + INSERT INTO sqlite_stat1 VALUES('t1','t1x3','10747267 260'); + INSERT INTO sqlite_stat1 VALUES('t1','t1x2','10747267 121 113 2 2 2 1'); + INSERT INTO sqlite_stat1 VALUES('t1','t1x1','10747267 50 40'); + INSERT INTO sqlite_stat1 VALUES('t1','t1x0','10747267 1'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x15','39667 253'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x14','39667 19834'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x13','39667 13223'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x12','39667 7'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x11','39667 17'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x10','39667 19834'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x9','39667 7934'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x8','39667 11'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x7','39667 5'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x6','39667 242'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x5','39667 1984'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x4','39667 4408'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x3','39667 81'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x2','39667 551'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x1','39667 2'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x0','39667 1'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x6','569 285'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x5','569 2'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x4','569 2'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x3','569 5'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x2','569 3'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x1','569 6'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x0','569 1'); + ANALYZE sqlite_master; +} {} +do_execsql_test autoindex2-120 { + EXPLAIN QUERY PLAN + SELECT + t1_id, + t1.did, + param2, + param3, + t1.ptime, + t1.trange, + t1.exmass, + t1.mass, + t1.vstatus, + type, + subtype, + t1.deviation, + t1.formula, + dparam1, + reserve1, + reserve2, + param4, + t1.last_operation, + t1.admin_uuid, + t1.previous_value, + t1.job_id, + client_did, + t1.last_t1, + t1.data_t1, + t1.previous_date, + param5, + param6, + mgr_uuid + FROM + t1, + t2, + t3 + WHERE + t1.ptime > 1393520400 + AND param3<>9001 + AND t3.flg7 = 1 + AND t1.did = t2.did + AND t2.uid = t3.uid + ORDER BY t1.ptime desc LIMIT 500; +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1x1 (ptime>?)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2x0 (did=?)} 0 2 2 {SEARCH TABLE t3 USING INDEX t3x0 (uid=?)}} +# +# ^^^--- Before being fixed, the above was using an automatic covering +# on t3 and reordering the tables so that t3 was in the outer loop and +# implementing the ORDER BY clause using a B-Tree. + +do_execsql_test autoindex2-120 { + EXPLAIN QUERY PLAN + SELECT + t1_id, + t1.did, + param2, + param3, + t1.ptime, + t1.trange, + t1.exmass, + t1.mass, + t1.vstatus, + type, + subtype, + t1.deviation, + t1.formula, + dparam1, + reserve1, + reserve2, + param4, + t1.last_operation, + t1.admin_uuid, + t1.previous_value, + t1.job_id, + client_did, + t1.last_t1, + t1.data_t1, + t1.previous_date, + param5, + param6, + mgr_uuid + FROM + t3, + t2, + t1 + WHERE + t1.ptime > 1393520400 + AND param3<>9001 + AND t3.flg7 = 1 + AND t1.did = t2.did + AND t2.uid = t3.uid + ORDER BY t1.ptime desc LIMIT 500; +} {0 0 2 {SEARCH TABLE t1 USING INDEX t1x1 (ptime>?)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2x0 (did=?)} 0 2 0 {SEARCH TABLE t3 USING INDEX t3x0 (uid=?)}} + +finish_test diff --git a/test/autoindex3.test b/test/autoindex3.test new file mode 100644 index 0000000..33053bb --- /dev/null +++ b/test/autoindex3.test @@ -0,0 +1,58 @@ +# 2014-06-17 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# +# This file implements regression tests for SQLite library. The +# focus of this script is testing automatic index creation logic, +# and specifically that an automatic index will not be created that +# shadows a declared index. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# The t1b and t2d indexes are not very selective. It used to be that +# the autoindex mechanism would create automatic indexes on t1(b) or +# t2(d), make assumptions that they were reasonably selective, and use +# them instead of t1b or t2d. But that would be cheating, because the +# automatic index cannot be any more selective than the real index. +# +# This test verifies that the cheat is no longer allowed. +# +do_execsql_test autoindex3-100 { + CREATE TABLE t1(a,b,x); + CREATE TABLE t2(c,d,y); + CREATE INDEX t1b ON t1(b); + CREATE INDEX t2d ON t2(d); + ANALYZE sqlite_master; + INSERT INTO sqlite_stat1 VALUES('t1','t1b','10000 500'); + INSERT INTO sqlite_stat1 VALUES('t2','t2d','10000 500'); + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d=b; +} {~/AUTO/} + +# Automatic indexes can still be used if existing indexes do not +# participate in == constraints. +# +do_execsql_test autoindex3-110 { + EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d>b AND x=y; +} {/AUTO/} +do_execsql_test autoindex3-120 { + EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d<b AND x=y; +} {/AUTO/} +do_execsql_test autoindex3-130 { + EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d IS NULL AND x=y; +} {/AUTO/} +do_execsql_test autoindex3-140 { + EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d IN (5,b) AND x=y; +} {/AUTO/} + + +finish_test diff --git a/test/autovacuum.test b/test/autovacuum.test index bba40e3..9ee2cd0 100644 --- a/test/autovacuum.test +++ b/test/autovacuum.test @@ -526,7 +526,7 @@ do_test autovacuum-4.2 { catchsql { CREATE UNIQUE INDEX av1_i ON av1(a); } -} {1 {indexed columns are not unique}} +} {1 {UNIQUE constraint failed: av1.a}} do_test autovacuum-4.3 { execsql { SELECT sum(a) FROM av1; diff --git a/test/backcompat.test b/test/backcompat.test index dd40fed..ea7e6a9 100644 --- a/test/backcompat.test +++ b/test/backcompat.test @@ -58,12 +58,24 @@ proc do_backcompat_test {rv bin1 bin2 script} { code1 { sqlite3 db test.db } code2 { sqlite3 db test.db } + foreach c {code1 code2} { + $c { + set v [split [db version] .] + if {[llength $v]==3} {lappend v 0} + set ::sqlite_libversion [format \ + "%d%.2d%.2d%2d" [lindex $v 0] [lindex $v 1] [lindex $v 2] [lindex $v 3] + ] + } + } + uplevel $script catch { code1 { db close } } catch { code2 { db close } } catch { close $::bc_chan2 } catch { close $::bc_chan1 } + + } array set ::incompatible [list] @@ -200,6 +212,42 @@ do_allbackcompat_test { do_test backcompat-1.2.7 { sql1 { PRAGMA integrity_check } } {ok} do_test backcompat-1.2.8 { sql2 { PRAGMA integrity_check } } {ok} + + do_test backcompat-2.1 { + sql1 { + CREATE TABLE t2(a UNIQUE, b PRIMARY KEY, c UNIQUE); + INSERT INTO t2 VALUES(1,9,5); + INSERT INTO t2 VALUES(5,5,1); + INSERT INTO t2 VALUES(9,1,9); + SELECT * FROM t2 ORDER BY a; + } + } {1 9 5 5 5 1 9 1 9} + do_test backcompat-2.2 { + sql2 { + SELECT * FROM sqlite_master WHERE rootpage=-1; + SELECT * FROM t2 ORDER BY a; + } + } {1 9 5 5 5 1 9 1 9} + do_test backcompat-2.3 { + sql1 { + SELECT * FROM t2 ORDER BY b; + } + } {9 1 9 5 5 1 1 9 5} + do_test backcompat-2.4 { + sql2 { + SELECT * FROM t2 ORDER BY b; + } + } {9 1 9 5 5 1 1 9 5} + do_test backcompat-2.5 { + sql1 { + SELECT * FROM t2 ORDER BY c; + } + } {5 5 1 1 9 5 9 1 9} + do_test backcompat-2.6 { + sql2 { + SELECT * FROM t2 ORDER BY c; + } + } {5 5 1 1 9 5 9 1 9} } foreach k [lsort [array names ::incompatible]] { puts "ERROR: Detected journal incompatibility with version $k" @@ -345,6 +393,48 @@ ifcapable fts3 { } { do_test backcompat-3.7 [list sql1 $q] [sql2 $q] } + + # Now test that an incremental merge can be started by one version + # and finished by another. And that the integrity-check still + # passes. + do_test backcompat-3.8 { + sql1 { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1(docid, words); + CREATE VIRTUAL TABLE t2 USING fts3(words); + } + code1 [list source $testdir/genesis.tcl] + code1 { fts_kjv_genesis } + sql1 { + INSERT INTO t2 SELECT words FROM t1; + INSERT INTO t2 SELECT words FROM t1; + INSERT INTO t2 SELECT words FROM t1; + INSERT INTO t2 SELECT words FROM t1; + INSERT INTO t2 SELECT words FROM t1; + INSERT INTO t2 SELECT words FROM t1; + SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level; + } + } {0 {0 1 2 3 4 5}} + + if {[code1 { set ::sqlite_libversion }] >=3071200 + && [code2 { set ::sqlite_libversion }] >=3071200 + } { + do_test backcompat-3.9 { + sql1 { INSERT INTO t2(t2) VALUES('merge=100,4'); } + sql2 { INSERT INTO t2(t2) VALUES('merge=100,4'); } + sql1 { INSERT INTO t2(t2) VALUES('merge=100,4'); } + sql2 { INSERT INTO t2(t2) VALUES('merge=2500,4'); } + sql2 { + SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level; + } + } {0 {0 1} 1 0} + + do_test backcompat-3.10 { + sql1 { INSERT INTO t2(t2) VALUES('integrity-check') } + sql2 { INSERT INTO t2(t2) VALUES('integrity-check') } + } {} + } } } } diff --git a/test/backup4.test b/test/backup4.test index a1a7735..417df80 100644 --- a/test/backup4.test +++ b/test/backup4.test @@ -101,4 +101,3 @@ do_test 3.3 { do_test 3.4 { file size test.db2 } 0 finish_test - diff --git a/test/between.test b/test/between.test index 4543675..df4c679 100644 --- a/test/between.test +++ b/test/between.test @@ -48,14 +48,24 @@ do_test between-1.0 { # This procedure executes the SQL. Then it appends to the result the # "sort" or "nosort" keyword depending on whether or not any sorting -# is done. Then it appends the ::sqlite_query_plan variable. +# is done. Then it appends the names of the table and index used. # proc queryplan {sql} { set ::sqlite_sort_count 0 set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x - return [concat $data $::sqlite_query_plan] + set eqp [execsql "EXPLAIN QUERY PLAN $sql"] + # puts eqp=$eqp + foreach {a b c x} $eqp { + if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ + $x all as tab idx]} { + lappend data $tab $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { + lappend data $tab * + } + } + return $data } do_test between-1.1.1 { @@ -67,7 +77,7 @@ do_test between-1.1.2 { queryplan { SELECT * FROM t1 WHERE +w BETWEEN 5 AND 6 ORDER BY +w } -} {5 2 36 38 6 2 49 51 sort t1 {}} +} {5 2 36 38 6 2 49 51 sort t1 *} do_test between-1.2.1 { queryplan { SELECT * FROM t1 WHERE w BETWEEN 5 AND 65-y ORDER BY +w @@ -77,7 +87,7 @@ do_test between-1.2.2 { queryplan { SELECT * FROM t1 WHERE +w BETWEEN 5 AND 65-y ORDER BY +w } -} {5 2 36 38 6 2 49 51 sort t1 {}} +} {5 2 36 38 6 2 49 51 sort t1 *} do_test between-1.3.1 { queryplan { SELECT * FROM t1 WHERE w BETWEEN 41-y AND 6 ORDER BY +w @@ -87,12 +97,12 @@ do_test between-1.3.2 { queryplan { SELECT * FROM t1 WHERE +w BETWEEN 41-y AND 6 ORDER BY +w } -} {5 2 36 38 6 2 49 51 sort t1 {}} +} {5 2 36 38 6 2 49 51 sort t1 *} do_test between-1.4 { queryplan { SELECT * FROM t1 WHERE w BETWEEN 41-y AND 65-y ORDER BY +w } -} {5 2 36 38 6 2 49 51 sort t1 {}} +} {5 2 36 38 6 2 49 51 sort t1 *} do_test between-1.5.1 { queryplan { SELECT * FROM t1 WHERE 26 BETWEEN y AND z ORDER BY +w @@ -107,7 +117,7 @@ do_test between-1.5.3 { queryplan { SELECT * FROM t1 WHERE 26 BETWEEN y AND +z ORDER BY +w } -} {4 2 25 27 sort t1 {}} +} {4 2 25 27 sort t1 *} finish_test diff --git a/test/bigfile2.test b/test/bigfile2.test index b67cb34..de3b14b 100644 --- a/test/bigfile2.test +++ b/test/bigfile2.test @@ -57,6 +57,6 @@ do_test 1.3 { } $str db close -file delete test.db +delete_file test.db finish_test diff --git a/test/boundary3.tcl b/test/boundary3.tcl index ac3bf0a..5fc26d6 100644 --- a/test/boundary3.tcl +++ b/test/boundary3.tcl @@ -13,7 +13,6 @@ puts {# 2008 December 11 # This file is automatically generated from a separate TCL script. # This file seeks to exercise integer boundary values. # -# $Id: boundary3.tcl,v 1.3 2009/01/02 15:45:48 shane Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -40,16 +39,16 @@ foreach x { } { set x [expr {wide($x)}] set boundarynum($x) 1 - set boundarynum([expr {$x+1}]) 1 - set boundarynum([expr {-($x+1)}]) 1 - set boundarynum([expr {-($x+2)}]) 1 - set boundarynum([expr {$x+$x+1}]) 1 - set boundarynum([expr {$x+$x+2}]) 1 + set boundarynum([expr {wide($x+1)}]) 1 + set boundarynum([expr {wide(-($x+1))}]) 1 + set boundarynum([expr {wide(-($x+2))}]) 1 + set boundarynum([expr {wide($x+$x+1)}]) 1 + set boundarynum([expr {wide($x+$x+2)}]) 1 } set x [expr {wide(127)}] for {set i 1} {$i<=9} {incr i} { set boundarynum($x) 1 - set boundarynum([expr {$x+1}]) 1 + set boundarynum([expr {wide($x+1)}]) 1 set x [expr {wide($x*128 + 127)}] } @@ -116,7 +115,7 @@ foreach r $nums1 { incr a set t1ra($r) $a set t1ar($a) $r - set x [format %08x%08x [expr {wide($r)>>32}] $r] + set x [format %016x [expr {wide($r)}]] set t1rx($r) $x set t1xr($x) $r puts " INSERT INTO t1(oid,a,x) VALUES($r,$a,'$x');" @@ -158,7 +157,7 @@ foreach r $nums3 { set r5 $r.5 set r0 $r.0 - if {abs($r)<9.22337203685477580800e+18} { + if {abs($r)<0x7FFFFFFFFFFFFFFF || $r==-9223372036854775808} { set x $t1rx($r) set a $t1ra($r) puts "do_test $tname-2.$i.1 \173" diff --git a/test/btreefault.test b/test/btreefault.test index 9b42240..61104c5 100644 --- a/test/btreefault.test +++ b/test/btreefault.test @@ -55,4 +55,3 @@ do_faultsim_test 1 -prep { } finish_test - diff --git a/test/capi2.test b/test/capi2.test index 20ee340..39f50dd 100644 --- a/test/capi2.test +++ b/test/capi2.test @@ -237,7 +237,7 @@ do_test capi2-3.13b {db changes} {0} do_test capi2-3.14 { list [sqlite3_finalize $VM] [sqlite3_errmsg $DB] \ [sqlite3_extended_errcode $DB] -} {SQLITE_CONSTRAINT {column a is not unique} SQLITE_CONSTRAINT_UNIQUE} +} {SQLITE_CONSTRAINT {UNIQUE constraint failed: t1.a} SQLITE_CONSTRAINT_UNIQUE} do_test capi2-3.15 { set VM [sqlite3_prepare $DB {CREATE TABLE t2(a NOT NULL, b)} -1 TAIL] set TAIL @@ -261,7 +261,7 @@ do_test capi2-3.18 { do_test capi2-3.19 { list [sqlite3_finalize $VM] [sqlite3_errmsg $DB] \ [sqlite3_extended_errcode $DB] -} {SQLITE_CONSTRAINT {t2.a may not be NULL} SQLITE_CONSTRAINT_NOTNULL} +} {SQLITE_CONSTRAINT {NOT NULL constraint failed: t2.a} SQLITE_CONSTRAINT_NOTNULL} do_test capi2-3.20 { execsql { @@ -555,7 +555,7 @@ do_test capi2-6.27 { INSERT INTO t1 VALUES(2,4,5); SELECT * FROM t1; } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test capi2-6.28 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ diff --git a/test/capi3.test b/test/capi3.test index 9d7434d..cbaa5c5 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -16,6 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set ::testprefix capi3 # Do not use a codec for tests in this file, as the database file is # manipulated directly using tcl scripts (using the [hexio_write] command). @@ -179,16 +180,18 @@ do_test capi3-3.4 { do_test capi3-3.5 { sqlite3_close $db2 } {SQLITE_OK} -do_test capi3-3.6.1-misuse { - sqlite3_close $db2 -} {SQLITE_MISUSE} -do_test capi3-3.6.2-misuse { - sqlite3_errmsg $db2 -} {library routine called out of sequence} -ifcapable {utf16} { - do_test capi3-3.6.3-misuse { - utf8 [sqlite3_errmsg16 $db2] +if {[clang_sanitize_address]==0} { + do_test capi3-3.6.1-misuse { + sqlite3_close $db2 + } {SQLITE_MISUSE} + do_test capi3-3.6.2-misuse { + sqlite3_errmsg $db2 } {library routine called out of sequence} + ifcapable {utf16} { + do_test capi3-3.6.3-misuse { + utf8 [sqlite3_errmsg16 $db2] + } {library routine called out of sequence} + } } do_test capi3-3.7 { @@ -661,10 +664,12 @@ do_test capi3-6.3 { sqlite3_finalize $STMT } {SQLITE_OK} -do_test capi3-6.4-misuse { - db cache flush - sqlite3_close $DB -} {SQLITE_OK} +if {[clang_sanitize_address]==0} { + do_test capi3-6.4-misuse { + db cache flush + sqlite3_close $DB + } {SQLITE_OK} +} db close # This procedure sets the value of the file-format in file 'test.db' @@ -1060,11 +1065,13 @@ if {[llength [info commands sqlite3_sleep]]>0} { } # Ticket #1219: Make sure binding APIs can handle a NULL pointer. -# -do_test capi3-14.1-misuse { - set rc [catch {sqlite3_bind_text 0 1 hello 5} msg] - lappend rc $msg -} {1 SQLITE_MISUSE} +# +if {[clang_sanitize_address]==0} { + do_test capi3-14.1-misuse { + set rc [catch {sqlite3_bind_text 0 1 hello 5} msg] + lappend rc $msg + } {1 SQLITE_MISUSE} +} # Ticket #1650: Honor the nBytes parameter to sqlite3_prepare. # @@ -1215,6 +1222,23 @@ do_test capi3-19.1 { sqlite3_prepare_tkt3134 db } {} +# Test that calling sqlite3_column_blob() on a TEXT value does not change +# the return type of subsequent calls to sqlite3_column_type(). +# +do_execsql_test 20.1 { + CREATE TABLE t4(x); + INSERT INTO t4 VALUES('abcdefghij'); +} +do_test 20.2 { + set stmt [sqlite3_prepare db "SELECT * FROM t4" -1 dummy] + sqlite3_step $stmt +} {SQLITE_ROW} +do_test 20.3 { sqlite3_column_type $stmt 0 } {TEXT} +do_test 20.4 { sqlite3_column_blob $stmt 0 } {abcdefghij} +do_test 20.5 { sqlite3_column_type $stmt 0 } {TEXT} +do_test 20.6 { sqlite3_finalize $stmt } SQLITE_OK + + # Tests of the interface when no VFS is registered. # if {![info exists tester_do_binarylog]} { diff --git a/test/capi3c.test b/test/capi3c.test index 14545c0..6388717 100644 --- a/test/capi3c.test +++ b/test/capi3c.test @@ -169,16 +169,18 @@ do_test capi3c-3.4 { do_test capi3c-3.5 { sqlite3_close $db2 } {SQLITE_OK} -do_test capi3c-3.6.1-misuse { - sqlite3_close $db2 -} {SQLITE_MISUSE} -do_test capi3c-3.6.2-misuse { - sqlite3_errmsg $db2 -} {library routine called out of sequence} -ifcapable {utf16} { - do_test capi3c-3.6.3-misuse { - utf8 [sqlite3_errmsg16 $db2] +if {[clang_sanitize_address]==0} { + do_test capi3c-3.6.1-misuse { + sqlite3_close $db2 + } {SQLITE_MISUSE} + do_test capi3c-3.6.2-misuse { + sqlite3_errmsg $db2 } {library routine called out of sequence} + ifcapable {utf16} { + do_test capi3c-3.6.3-misuse { + utf8 [sqlite3_errmsg16 $db2] + } {library routine called out of sequence} + } } # rename sqlite3_open "" @@ -627,13 +629,17 @@ check_data $STMT capi3c-6.3 {INTEGER} {1} {1.0} {1} do_test capi3c-6.3 { sqlite3_finalize $STMT } {SQLITE_OK} -do_test capi3c-6.4 { - db cache flush - sqlite3_close $DB -} {SQLITE_OK} -do_test capi3c-6.99-misuse { +if {[clang_sanitize_address]==0} { + do_test capi3c-6.4 { + db cache flush + sqlite3_close $DB + } {SQLITE_OK} + do_test capi3c-6.99-misuse { + db close + } {} +} else { db close -} {} +} # This procedure sets the value of the file-format in file 'test.db' # to $newval. Also, the schema cookie is incremented. diff --git a/test/capi3d.test b/test/capi3d.test index 746ec20..fb8abe8 100644 --- a/test/capi3d.test +++ b/test/capi3d.test @@ -108,6 +108,13 @@ db eval {CREATE TABLE t1(x)} test_is_readonly capi3d-2.3 {INSERT INTO t1 VALUES(5)} 0 test_is_readonly capi3d-2.4 {UPDATE t1 SET x=x+1 WHERE x<0} 0 test_is_readonly capi3d-2.5 {SELECT * FROM t1} 1 +ifcapable wal { + test_is_readonly capi3d-2.6 {PRAGMA journal_mode=WAL} 0 + test_is_readonly capi3d-2.7 {PRAGMA wal_checkpoint} 0 +} +test_is_readonly capi3d-2.8 {PRAGMA application_id=1234} 0 +test_is_readonly capi3d-2.9 {VACUUM} 0 +test_is_readonly capi3d-2.10 {PRAGMA integrity_check} 1 do_test capi3-2.99 { sqlite3_stmt_readonly 0 } 1 @@ -137,4 +144,41 @@ do_test capi3d-3.99 { sqlite3_stmt_busy 0 } {0} +#-------------------------------------------------------------------------- +# Test the sqlite3_stmt_busy() function with ROLLBACK statements. +# +reset_db + +do_execsql_test capi3d-4.1 { + CREATE TABLE t4(x,y); + BEGIN; +} + +do_test capi3d-4.2.1 { + breakpoint + set ::s1 [sqlite3_prepare_v2 db "ROLLBACK" -1 notused] + sqlite3_step $::s1 +} {SQLITE_DONE} + +do_test capi3d-4.2.2 { + sqlite3_stmt_busy $::s1 +} {1} + +do_catchsql_test capi3d-4.2.3 { + VACUUM +} {1 {cannot VACUUM - SQL statements in progress}} + +do_test capi3d-4.2.4 { + sqlite3_reset $::s1 +} {SQLITE_OK} + +do_catchsql_test capi3d-4.2.5 { + VACUUM +} {0 {}} + +do_test capi3d-4.2.6 { + sqlite3_finalize $::s1 +} {SQLITE_OK} + + finish_test diff --git a/test/capi3e.test b/test/capi3e.test index 21304cb..3e478e7 100644 --- a/test/capi3e.test +++ b/test/capi3e.test @@ -20,7 +20,11 @@ source $testdir/tester.tcl # Make sure the system encoding is utf-8. Otherwise, if the system encoding # is other than utf-8, [file isfile $x] may not refer to the same file # as [sqlite3 db $x]. -encoding system utf-8 +# +# This is no longer needed here because it should be done within the test +# fixture executable itself, via Tcl_SetSystemEncoding. +# +# encoding system utf-8 # Do not use a codec for tests in this file, as the database file is # manipulated directly using tcl scripts (using the [hexio_write] command). @@ -60,7 +64,7 @@ proc utf8 {str} { db close # here's the list of file names we're testing -set names {t 1 t. 1. t.d 1.d t-1 1-1 t.db ä.db ë.db ö.db ü.db ÿ.db} +set names {t 1 t. 1. t.d 1.d t-1 1-1 t.db ä.db ë.db ö.db ü.db ÿ.db} set i 0 foreach name $names { diff --git a/test/check.test b/test/check.test index 99b72ac..02b99f2 100644 --- a/test/check.test +++ b/test/check.test @@ -41,7 +41,7 @@ do_test check-1.3 { catchsql { INSERT INTO t1 VALUES(6,7); } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} do_test check-1.4 { execsql { SELECT * FROM t1; @@ -51,7 +51,7 @@ do_test check-1.5 { catchsql { INSERT INTO t1 VALUES(4,3); } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} do_test check-1.6 { execsql { SELECT * FROM t1; @@ -88,7 +88,7 @@ do_test check-1.12 { catchsql { UPDATE t1 SET x=7 WHERE x==2 } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} do_test check-1.13 { execsql { SELECT * FROM t1; @@ -98,7 +98,7 @@ do_test check-1.14 { catchsql { UPDATE t1 SET x=5 WHERE x==2 } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} do_test check-1.15 { execsql { SELECT * FROM t1; @@ -142,17 +142,17 @@ do_test check-2.4 { catchsql { INSERT INTO t2 VALUES(1.1, NULL, NULL); } -} {1 {constraint one failed}} +} {1 {CHECK constraint failed: one}} do_test check-2.5 { catchsql { INSERT INTO t2 VALUES(NULL, 5, NULL); } -} {1 {constraint two failed}} +} {1 {CHECK constraint failed: two}} do_test check-2.6 { catchsql { INSERT INTO t2 VALUES(NULL, NULL, 3.14159); } -} {1 {constraint three failed}} +} {1 {CHECK constraint failed: three}} # Undocumented behavior: The CONSTRAINT name clause can follow a constraint. # Such a clause is ignored. But the parser must accept it for backwards @@ -172,7 +172,7 @@ do_test check-2.11 { catchsql { INSERT INTO t2b VALUES('xyzzy','hi',5); } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t2b}} do_test check-2.12 { execsql { CREATE TABLE t2c( @@ -188,7 +188,7 @@ do_test check-2.13 { catchsql { INSERT INTO t2c VALUES('xyzzy',7,8); } -} {1 {constraint x_two failed}} +} {1 {CHECK constraint failed: x_two}} do_test check-2.cleanup { execsql { DROP TABLE IF EXISTS t2b; @@ -256,7 +256,7 @@ do_test check-3.9 { catchsql { INSERT INTO t3 VALUES(111,222,333); } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t3}} do_test check-4.1 { execsql { @@ -298,7 +298,7 @@ do_test check-4.6 { catchsql { UPDATE t4 SET x=0, y=1; } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t4}} do_test check-4.7 { execsql { SELECT * FROM t4; @@ -316,7 +316,7 @@ do_test check-4.9 { PRAGMA ignore_check_constraints=OFF; UPDATE t4 SET x=0, y=2; } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t4}} ifcapable vacuum { do_test check_4.10 { catchsql { @@ -367,7 +367,7 @@ do_test check-6.5 { catchsql { UPDATE OR FAIL t1 SET x=7-x, y=y+1; } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} do_test check-6.6 { execsql { SELECT * FROM t1; @@ -379,7 +379,7 @@ do_test check-6.7 { INSERT INTO t1 VALUES(1,30.0); INSERT OR ROLLBACK INTO t1 VALUES(8,40.0); } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} do_test check-6.8 { catchsql { COMMIT; @@ -398,7 +398,7 @@ do_test check-6.12 { catchsql { REPLACE INTO t1 VALUES(6,7); } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} do_test check-6.13 { execsql {SELECT * FROM t1} } {3 12.0 2 20.0} @@ -426,7 +426,8 @@ db func myfunc myfunc do_execsql_test 7.1 { CREATE TABLE t6(a CHECK (myfunc(a))) } do_execsql_test 7.2 { INSERT INTO t6 VALUES(9) } -do_catchsql_test 7.3 { INSERT INTO t6 VALUES(11) } {1 {constraint failed}} +do_catchsql_test 7.3 { INSERT INTO t6 VALUES(11) } \ + {1 {CHECK constraint failed: t6}} do_test 7.4 { sqlite3 db2 test.db @@ -449,7 +450,13 @@ do_test 7.7 { do_test 7.8 { db2 func myfunc myfunc catchsql { INSERT INTO t6 VALUES(12) } db2 -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t6}} +# 2013-08-02: Silently ignore database name qualifiers in CHECK constraints. +# +do_execsql_test 8.1 { + CREATE TABLE t810(a, CHECK( main.t810.a>0 )); + CREATE TABLE t811(b, CHECK( xyzzy.t811.b BETWEEN 5 AND 10 )); +} {} finish_test diff --git a/test/close.test b/test/close.test index 355a886..d5d6391 100644 --- a/test/close.test +++ b/test/close.test @@ -76,4 +76,3 @@ do_test 1.4.4 { } {SQLITE_OK} finish_test - diff --git a/test/closure01.test b/test/closure01.test index 5dac87a..213ef4e 100644 --- a/test/closure01.test +++ b/test/closure01.test @@ -15,51 +15,68 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix closure01 -ifcapable !vtab { finish_test ; return } +ifcapable !vtab||!cte { finish_test ; return } load_static_extension db closure do_execsql_test 1.0 { BEGIN; CREATE TABLE t1(x INTEGER PRIMARY KEY, y INTEGER); + WITH RECURSIVE + cnt(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM cnt LIMIT 131072) + INSERT INTO t1(x, y) SELECT i, nullif(i,1)/2 FROM cnt; CREATE INDEX t1y ON t1(y); - INSERT INTO t1(x) VALUES(1),(2); - INSERT INTO t1(x) SELECT x+2 FROM t1; - INSERT INTO t1(x) SELECT x+4 FROM t1; - INSERT INTO t1(x) SELECT x+8 FROM t1; - INSERT INTO t1(x) SELECT x+16 FROM t1; - INSERT INTO t1(x) SELECT x+32 FROM t1; - INSERT INTO t1(x) SELECT x+64 FROM t1; - INSERT INTO t1(x) SELECT x+128 FROM t1; - INSERT INTO t1(x) SELECT x+256 FROM t1; - INSERT INTO t1(x) SELECT x+512 FROM t1; - INSERT INTO t1(x) SELECT x+1024 FROM t1; - INSERT INTO t1(x) SELECT x+2048 FROM t1; - INSERT INTO t1(x) SELECT x+4096 FROM t1; - INSERT INTO t1(x) SELECT x+8192 FROM t1; - INSERT INTO t1(x) SELECT x+16384 FROM t1; - INSERT INTO t1(x) SELECT x+32768 FROM t1; - INSERT INTO t1(x) SELECT x+65536 FROM t1; - UPDATE t1 SET y=x/2 WHERE x>1; COMMIT; CREATE VIRTUAL TABLE cx USING transitive_closure(tablename=t1, idcolumn=x, parentcolumn=y); } {} # The entire table -do_execsql_test 1.1 { +do_timed_execsql_test 1.1 { SELECT count(*), depth FROM cx WHERE root=1 GROUP BY depth ORDER BY 1; } {/1 0 1 17 2 1 4 2 8 3 16 4 .* 65536 16/} +do_timed_execsql_test 1.1-cte { + WITH RECURSIVE + below(id,depth) AS ( + VALUES(1,0) + UNION ALL + SELECT t1.x, below.depth+1 + FROM t1 JOIN below on t1.y=below.id + ) + SELECT count(*), depth FROM below GROUP BY depth ORDER BY 1; +} {/1 0 1 17 2 1 4 2 8 3 16 4 .* 65536 16/} # descendents of 32768 -do_execsql_test 1.2 { +do_timed_execsql_test 1.2 { SELECT * FROM cx WHERE root=32768 ORDER BY id; } {32768 0 65536 1 65537 1 131072 2} +do_timed_execsql_test 1.2-cte { + WITH RECURSIVE + below(id,depth) AS ( + VALUES(32768,0) + UNION ALL + SELECT t1.x, below.depth+1 + FROM t1 JOIN below on t1.y=below.id + WHERE below.depth<2 + ) + SELECT id, depth FROM below ORDER BY id; +} {32768 0 65536 1 65537 1 131072 2} # descendents of 16384 -do_execsql_test 1.3 { +do_timed_execsql_test 1.3 { SELECT * FROM cx WHERE root=16384 AND depth<=2 ORDER BY id; } {16384 0 32768 1 32769 1 65536 2 65537 2 65538 2 65539 2} +do_timed_execsql_test 1.3-cte { + WITH RECURSIVE + below(id,depth) AS ( + VALUES(16384,0) + UNION ALL + SELECT t1.x, below.depth+1 + FROM t1 JOIN below on t1.y=below.id + WHERE below.depth<2 + ) + SELECT id, depth FROM below ORDER BY id; +} {16384 0 32768 1 32769 1 65536 2 65537 2 65538 2 65539 2} # children of 16384 do_execsql_test 1.4 { @@ -70,19 +87,41 @@ do_execsql_test 1.4 { } {32768 1 {} t1 x y 32769 1 {} t1 x y} # great-grandparent of 16384 -do_execsql_test 1.5 { +do_timed_execsql_test 1.5 { SELECT id, depth, root, tablename, idcolumn, parentcolumn FROM cx WHERE root=16384 AND depth=3 AND idcolumn='Y' AND parentcolumn='X'; } {2048 3 {} t1 Y X} +do_timed_execsql_test 1.5-cte { + WITH RECURSIVE + above(id,depth) AS ( + VALUES(16384,0) + UNION ALL + SELECT t1.y, above.depth+1 + FROM t1 JOIN above ON t1.x=above.id + WHERE above.depth<3 + ) + SELECT id FROM above WHERE depth=3; +} {2048} # depth<5 -do_execsql_test 1.6 { +do_timed_execsql_test 1.6 { SELECT count(*), depth FROM cx WHERE root=1 AND depth<5 GROUP BY depth ORDER BY 1; } {1 0 2 1 4 2 8 3 16 4} +do_timed_execsql_test 1.6-cte { + WITH RECURSIVE + below(id,depth) AS ( + VALUES(1,0) + UNION ALL + SELECT t1.x, below.depth+1 + FROM t1 JOIN below ON t1.y=below.id + WHERE below.depth<4 + ) + SELECT count(*), depth FROM below GROUP BY depth ORDER BY 1; +} {1 0 2 1 4 2 8 3 16 4} # depth<=5 do_execsql_test 1.7 { @@ -103,9 +142,20 @@ do_execsql_test 1.9 { } {8 3 16 4 32 5} # depth==5 with min() and max() -do_execsql_test 1.10 { +do_timed_execsql_test 1.10 { SELECT count(*), min(id), max(id) FROM cx WHERE root=1 AND depth=5; } {32 32 63} +do_timed_execsql_test 1.10-cte { + WITH RECURSIVE + below(id,depth) AS ( + VALUES(1,0) + UNION ALL + SELECT t1.x, below.depth+1 + FROM t1 JOIN below ON t1.y=below.id + WHERE below.depth<5 + ) + SELECT count(*), min(id), max(id) FROM below WHERE depth=5; +} {32 32 63} # Create a much smaller table t2 with only 32 elements db eval { diff --git a/test/collate1.test b/test/collate1.test index b493ee8..2085415 100644 --- a/test/collate1.test +++ b/test/collate1.test @@ -75,7 +75,6 @@ do_test collate1-1.1 { } } {{} 0x119 0x2D} do_test collate1-1.2 { -breakpoint execsql { SELECT c2 FROM collate1t1 ORDER BY 1 COLLATE hex; } @@ -305,4 +304,33 @@ do_test collate1-4.5 { } } {} +# A problem reported on the mailing list: A CREATE TABLE statement +# is allowed to have two or more COLLATE clauses on the same column. +# That probably ought to be an error, but we allow it for backwards +# compatibility. Just make sure it works and doesn't leak memory. +# +do_test collate1-5.1 { + execsql { + CREATE TABLE c5( + id INTEGER PRIMARY KEY, + a TEXT COLLATE binary COLLATE nocase COLLATE rtrim, + b TEXT COLLATE nocase COLLATE binary, + c TEXT COLLATE rtrim COLLATE binary COLLATE rtrim COLLATE nocase + ); + INSERT INTO c5 VALUES(1, 'abc','abc','abc'); + INSERT INTO c5 VALUES(2, 'abc ','ABC','ABC'); + SELECT id FROM c5 WHERE a='abc' ORDER BY id; + } +} {1 2} +do_test collate1-5.2 { + execsql { + SELECT id FROM c5 WHERE b='abc' ORDER BY id; + } +} {1} +do_test collate1-5.3 { + execsql { + SELECT id FROM c5 WHERE c='abc' ORDER BY id; + } +} {1 2} + finish_test diff --git a/test/collate2.test b/test/collate2.test index bf61923..d5aadb4 100644 --- a/test/collate2.test +++ b/test/collate2.test @@ -17,6 +17,8 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set ::testprefix collate2 + # # Tests are organised as follows: # @@ -636,13 +638,15 @@ do_test collate2-4.2 { do_test collate2-4.3 { execsql { SELECT collate2t1.a FROM collate2t1, collate2t3 - WHERE collate2t1.b = collate2t3.b||''; + WHERE collate2t1.b = collate2t3.b||'' + ORDER BY +collate2t1.a DESC; } } {aa aA Aa AA} do_test collate2-4.4 { execsql { SELECT collate2t1.a FROM collate2t1, collate2t3 - WHERE collate2t3.b||'' = collate2t1.b; + WHERE collate2t3.b||'' = collate2t1.b + ORDER BY +collate2t1.a DESC; } } {aa aA Aa AA} @@ -691,4 +695,30 @@ do_test collate2-5.5 { } } {aa aa} +do_execsql_test 6.1 { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('b'); + INSERT INTO t1 VALUES('B'); +} +do_execsql_test 6.2 { + SELECT * FROM t1 WHERE x COLLATE nocase BETWEEN 'a' AND 'c'; +} {b B} +do_execsql_test 6.3 { + SELECT * FROM t1 WHERE x BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase; +} {b B} +do_execsql_test 6.4 { + SELECT * FROM t1 + WHERE x COLLATE nocase BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase; +} {b B} +do_execsql_test 6.5 { + SELECT * FROM t1 WHERE +x COLLATE nocase BETWEEN 'a' AND 'c'; +} {b B} +do_execsql_test 6.6 { + SELECT * FROM t1 WHERE +x BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase; +} {b B} +do_execsql_test 6.7 { + SELECT * FROM t1 + WHERE +x COLLATE nocase BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase; +} {b B} + finish_test diff --git a/test/collate4.test b/test/collate4.test index 5ae1e7b..2ddf53d 100644 --- a/test/collate4.test +++ b/test/collate4.test @@ -473,7 +473,7 @@ do_test collate4-3.1 { INSERT INTO collate4t1 VALUES('abc'); INSERT INTO collate4t1 VALUES('ABC'); } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: collate4t1.a}} do_test collate4-3.2 { execsql { SELECT * FROM collate4t1; @@ -483,13 +483,13 @@ do_test collate4-3.3 { catchsql { INSERT INTO collate4t1 SELECT upper(a) FROM collate4t1; } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: collate4t1.a}} do_test collate4-3.4 { catchsql { INSERT INTO collate4t1 VALUES(1); UPDATE collate4t1 SET a = 'abc'; } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: collate4t1.a}} do_test collate4-3.5 { execsql { DROP TABLE collate4t1; @@ -501,7 +501,7 @@ do_test collate4-3.6 { INSERT INTO collate4t1 VALUES('abc'); INSERT INTO collate4t1 VALUES('ABC'); } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: collate4t1.a}} do_test collate4-3.7 { execsql { SELECT * FROM collate4t1; @@ -511,13 +511,13 @@ do_test collate4-3.8 { catchsql { INSERT INTO collate4t1 SELECT upper(a) FROM collate4t1; } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: collate4t1.a}} do_test collate4-3.9 { catchsql { INSERT INTO collate4t1 VALUES(1); UPDATE collate4t1 SET a = 'abc'; } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: collate4t1.a}} do_test collate4-3.10 { execsql { DROP TABLE collate4t1; @@ -530,7 +530,7 @@ do_test collate4-3.11 { INSERT INTO collate4t1 VALUES('abc'); INSERT INTO collate4t1 VALUES('ABC'); } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: collate4t1.a}} do_test collate4-3.12 { execsql { SELECT * FROM collate4t1; @@ -540,13 +540,13 @@ do_test collate4-3.13 { catchsql { INSERT INTO collate4t1 SELECT upper(a) FROM collate4t1; } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: collate4t1.a}} do_test collate4-3.14 { catchsql { INSERT INTO collate4t1 VALUES(1); UPDATE collate4t1 SET a = 'abc'; } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: collate4t1.a}} do_test collate4-3.15 { execsql { diff --git a/test/conflict.test b/test/conflict.test index 6576959..af5668e 100644 --- a/test/conflict.test +++ b/test/conflict.test @@ -242,7 +242,7 @@ foreach {i conf1 cmd t0 t1 t2} { 15 {} {INSERT OR ABORT} 1 {} 1 16 {} {INSERT OR ROLLBACK} 1 {} {} } { - if {$t0} {set t1 {t1.c may not be NULL}} + if {$t0} {set t1 {NOT NULL constraint failed: t1.c}} do_test conflict-5.$i { if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"} set r0 [catch {execsql [subst { @@ -306,7 +306,7 @@ foreach {i conf1 cmd t0 t1 t2 t3 t4} { 15 {} {UPDATE OR ABORT} 1 {1 2 3 4} 1 0 1 16 {} {UPDATE OR ROLLBACK} 1 {1 2 3 4} 0 0 0 } { - if {$t0} {set t1 {column a is not unique}} + if {$t0} {set t1 {UNIQUE constraint failed: t1.a}} if {[info exists TEMP_STORE] && $TEMP_STORE==3} { set t3 0 } else { @@ -493,13 +493,13 @@ do_test conflict-9.5 { INSERT INTO t2 VALUES(3,1,3,3,3); SELECT * FROM t2; } -} {1 {column b is not unique}} +} {1 {UNIQUE constraint failed: t2.b}} do_test conflict-9.6 { catchsql { UPDATE t2 SET b=b+1 WHERE b=1; SELECT * FROM t2; } -} {1 {column b is not unique}} +} {1 {UNIQUE constraint failed: t2.b}} do_test conflict-9.7 { catchsql { BEGIN; @@ -507,7 +507,7 @@ do_test conflict-9.7 { INSERT INTO t2 VALUES(3,1,3,3,3); SELECT * FROM t2; } -} {1 {column b is not unique}} +} {1 {UNIQUE constraint failed: t2.b}} do_test conflict-9.8 { execsql {COMMIT} execsql {SELECT * FROM t3} @@ -519,7 +519,7 @@ do_test conflict-9.9 { UPDATE t2 SET b=b+1 WHERE b=1; SELECT * FROM t2; } -} {1 {column b is not unique}} +} {1 {UNIQUE constraint failed: t2.b}} do_test conflict-9.10 { execsql {COMMIT} execsql {SELECT * FROM t3} @@ -529,13 +529,13 @@ do_test conflict-9.11 { INSERT INTO t2 VALUES(3,3,3,1,3); SELECT * FROM t2; } -} {1 {column d is not unique}} +} {1 {UNIQUE constraint failed: t2.d}} do_test conflict-9.12 { catchsql { UPDATE t2 SET d=d+1 WHERE d=1; SELECT * FROM t2; } -} {1 {column d is not unique}} +} {1 {UNIQUE constraint failed: t2.d}} do_test conflict-9.13 { catchsql { BEGIN; @@ -543,7 +543,7 @@ do_test conflict-9.13 { INSERT INTO t2 VALUES(3,3,3,1,3); SELECT * FROM t2; } -} {1 {column d is not unique}} +} {1 {UNIQUE constraint failed: t2.d}} do_test conflict-9.14 { execsql {COMMIT} execsql {SELECT * FROM t3} @@ -555,7 +555,7 @@ do_test conflict-9.15 { UPDATE t2 SET d=d+1 WHERE d=1; SELECT * FROM t2; } -} {1 {column d is not unique}} +} {1 {UNIQUE constraint failed: t2.d}} do_test conflict-9.16 { execsql {COMMIT} execsql {SELECT * FROM t3} @@ -565,13 +565,13 @@ do_test conflict-9.17 { INSERT INTO t2 VALUES(3,3,3,3,1); SELECT * FROM t2; } -} {1 {column e is not unique}} +} {1 {UNIQUE constraint failed: t2.e}} do_test conflict-9.18 { catchsql { UPDATE t2 SET e=e+1 WHERE e=1; SELECT * FROM t2; } -} {1 {column e is not unique}} +} {1 {UNIQUE constraint failed: t2.e}} do_test conflict-9.19 { catchsql { BEGIN; @@ -579,7 +579,7 @@ do_test conflict-9.19 { INSERT INTO t2 VALUES(3,3,3,3,1); SELECT * FROM t2; } -} {1 {column e is not unique}} +} {1 {UNIQUE constraint failed: t2.e}} verify_ex_errcode conflict-9.21b SQLITE_CONSTRAINT_UNIQUE do_test conflict-9.20 { catch {execsql {COMMIT}} @@ -592,7 +592,7 @@ do_test conflict-9.21 { UPDATE t2 SET e=e+1 WHERE e=1; SELECT * FROM t2; } -} {1 {column e is not unique}} +} {1 {UNIQUE constraint failed: t2.e}} verify_ex_errcode conflict-9.21b SQLITE_CONSTRAINT_UNIQUE do_test conflict-9.22 { catch {execsql {COMMIT}} @@ -782,7 +782,7 @@ do_test conflict-12.3 { catchsql { UPDATE t5 SET a=a+1 WHERE a=1; } -} {1 {PRIMARY KEY must be unique}} +} {1 {UNIQUE constraint failed: t5.a}} verify_ex_errcode conflict-12.3b SQLITE_CONSTRAINT_PRIMARYKEY do_test conflict-12.4 { execsql { @@ -790,6 +790,14 @@ do_test conflict-12.4 { SELECT * FROM t5; } } {2 one} +do_test conflict-12.5 { + catchsql { + CREATE TABLE t5b(x); + INSERT INTO t5b(rowid, x) VALUES(1,10),(2,11); + UPDATE t5b SET rowid=rowid+1 WHERE x=10; + } +} {1 {UNIQUE constraint failed: t5b.rowid}} +verify_ex_errcode conflict-12.5b SQLITE_CONSTRAINT_ROWID # Ticket [c38baa3d969eab7946dc50ba9d9b4f0057a19437] @@ -804,7 +812,7 @@ do_test conflict-13.1 { catchsql { REPLACE INTO t13 VALUES(2); } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t13}} verify_ex_errcode conflict-13.1b SQLITE_CONSTRAINT_CHECK do_test conflict-13.2 { execsql { diff --git a/test/conflict2.test b/test/conflict2.test new file mode 100644 index 0000000..8419f1a --- /dev/null +++ b/test/conflict2.test @@ -0,0 +1,855 @@ +# 2013-11-04 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests for the conflict resolution extension +# in WITHOUT ROWID tables +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !conflict { + finish_test + return +} + +# Create tables for the first group of tests. +# +do_test conflict2-1.0 { + execsql { + CREATE TABLE t1(a, b, c, PRIMARY KEY(a,b)) WITHOUT rowid; + CREATE TABLE t2(x); + SELECT c FROM t1 ORDER BY c; + } +} {} + +# Six columns of configuration data as follows: +# +# i The reference number of the test +# cmd An INSERT or REPLACE command to execute against table t1 +# t0 True if there is an error from $cmd +# t1 Content of "c" column of t1 assuming no error in $cmd +# t2 Content of "x" column of t2 +# t3 Number of temporary files created by this test +# +foreach {i cmd t0 t1 t2 t3} { + 1 INSERT 1 {} 1 0 + 2 {INSERT OR IGNORE} 0 3 1 0 + 3 {INSERT OR REPLACE} 0 4 1 0 + 4 REPLACE 0 4 1 0 + 5 {INSERT OR FAIL} 1 {} 1 0 + 6 {INSERT OR ABORT} 1 {} 1 0 + 7 {INSERT OR ROLLBACK} 1 {} {} 0 +} { + do_test conflict2-1.$i { + set ::sqlite_opentemp_count 0 + set r0 [catch {execsql [subst { + DELETE FROM t1; + DELETE FROM t2; + INSERT INTO t1 VALUES(1,2,3); + BEGIN; + INSERT INTO t2 VALUES(1); + $cmd INTO t1 VALUES(1,2,4); + }]} r1] + catch {execsql {COMMIT}} + if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]} + set r2 [execsql {SELECT x FROM t2}] + set r3 $::sqlite_opentemp_count + list $r0 $r1 $r2 $r3 + } [list $t0 $t1 $t2 $t3] +} + +# Create tables for the first group of tests. +# +do_test conflict2-2.0 { + execsql { + DROP TABLE t1; + DROP TABLE t2; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(a,b)) WITHOUT rowid; + CREATE TABLE t2(x); + SELECT c FROM t1 ORDER BY c; + } +} {} + +# Six columns of configuration data as follows: +# +# i The reference number of the test +# cmd An INSERT or REPLACE command to execute against table t1 +# t0 True if there is an error from $cmd +# t1 Content of "c" column of t1 assuming no error in $cmd +# t2 Content of "x" column of t2 +# +foreach {i cmd t0 t1 t2} { + 1 INSERT 1 {} 1 + 2 {INSERT OR IGNORE} 0 3 1 + 3 {INSERT OR REPLACE} 0 4 1 + 4 REPLACE 0 4 1 + 5 {INSERT OR FAIL} 1 {} 1 + 6 {INSERT OR ABORT} 1 {} 1 + 7 {INSERT OR ROLLBACK} 1 {} {} +} { + do_test conflict2-2.$i { + set r0 [catch {execsql [subst { + DELETE FROM t1; + DELETE FROM t2; + INSERT INTO t1 VALUES(1,2,3); + BEGIN; + INSERT INTO t2 VALUES(1); + $cmd INTO t1 VALUES(1,2,4); + }]} r1] + catch {execsql {COMMIT}} + if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]} + set r2 [execsql {SELECT x FROM t2}] + list $r0 $r1 $r2 + } [list $t0 $t1 $t2] +} + +# Create tables for the first group of tests. +# +do_test conflict2-3.0 { + execsql { + DROP TABLE t1; + DROP TABLE t2; + CREATE TABLE t1(a, b, c INTEGER, PRIMARY KEY(c), UNIQUE(a,b)) WITHOUT rowid; + CREATE TABLE t2(x); + SELECT c FROM t1 ORDER BY c; + } +} {} + +# Six columns of configuration data as follows: +# +# i The reference number of the test +# cmd An INSERT or REPLACE command to execute against table t1 +# t0 True if there is an error from $cmd +# t1 Content of "c" column of t1 assuming no error in $cmd +# t2 Content of "x" column of t2 +# +foreach {i cmd t0 t1 t2} { + 1 INSERT 1 {} 1 + 2 {INSERT OR IGNORE} 0 3 1 + 3 {INSERT OR REPLACE} 0 4 1 + 4 REPLACE 0 4 1 + 5 {INSERT OR FAIL} 1 {} 1 + 6 {INSERT OR ABORT} 1 {} 1 + 7 {INSERT OR ROLLBACK} 1 {} {} +} { + do_test conflict2-3.$i { + set r0 [catch {execsql [subst { + DELETE FROM t1; + DELETE FROM t2; + INSERT INTO t1 VALUES(1,2,3); + BEGIN; + INSERT INTO t2 VALUES(1); + $cmd INTO t1 VALUES(1,2,4); + }]} r1] + catch {execsql {COMMIT}} + if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]} + set r2 [execsql {SELECT x FROM t2}] + list $r0 $r1 $r2 + } [list $t0 $t1 $t2] +} + +do_test conflict2-4.0 { + execsql { + DROP TABLE t2; + CREATE TABLE t2(x); + SELECT x FROM t2; + } +} {} + +# Six columns of configuration data as follows: +# +# i The reference number of the test +# conf1 The conflict resolution algorithm on the UNIQUE constraint +# cmd An INSERT or REPLACE command to execute against table t1 +# t0 True if there is an error from $cmd +# t1 Content of "c" column of t1 assuming no error in $cmd +# t2 Content of "x" column of t2 +# +foreach {i conf1 cmd t0 t1 t2} { + 1 {} INSERT 1 {} 1 + 2 REPLACE INSERT 0 4 1 + 3 IGNORE INSERT 0 3 1 + 4 FAIL INSERT 1 {} 1 + 5 ABORT INSERT 1 {} 1 + 6 ROLLBACK INSERT 1 {} {} + 7 REPLACE {INSERT OR IGNORE} 0 3 1 + 8 IGNORE {INSERT OR REPLACE} 0 4 1 + 9 FAIL {INSERT OR IGNORE} 0 3 1 + 10 ABORT {INSERT OR REPLACE} 0 4 1 + 11 ROLLBACK {INSERT OR IGNORE } 0 3 1 +} { + do_test conflict2-4.$i { + if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"} + set r0 [catch {execsql [subst { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,PRIMARY KEY(a,b) $conf1) WITHOUT rowid; + DELETE FROM t2; + INSERT INTO t1 VALUES(1,2,3); + BEGIN; + INSERT INTO t2 VALUES(1); + $cmd INTO t1 VALUES(1,2,4); + }]} r1] + catch {execsql {COMMIT}} + if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]} + set r2 [execsql {SELECT x FROM t2}] + list $r0 $r1 $r2 + } [list $t0 $t1 $t2] +} + +do_test conflict2-5.0 { + execsql { + DROP TABLE t2; + CREATE TABLE t2(x); + SELECT x FROM t2; + } +} {} + +# Six columns of configuration data as follows: +# +# i The reference number of the test +# conf1 The conflict resolution algorithm on the NOT NULL constraint +# cmd An INSERT or REPLACE command to execute against table t1 +# t0 True if there is an error from $cmd +# t1 Content of "c" column of t1 assuming no error in $cmd +# t2 Content of "x" column of t2 +# +foreach {i conf1 cmd t0 t1 t2} { + 1 {} INSERT 1 {} 1 + 2 REPLACE INSERT 0 5 1 + 3 IGNORE INSERT 0 {} 1 + 4 FAIL INSERT 1 {} 1 + 5 ABORT INSERT 1 {} 1 + 6 ROLLBACK INSERT 1 {} {} + 7 REPLACE {INSERT OR IGNORE} 0 {} 1 + 8 IGNORE {INSERT OR REPLACE} 0 5 1 + 9 FAIL {INSERT OR IGNORE} 0 {} 1 + 10 ABORT {INSERT OR REPLACE} 0 5 1 + 11 ROLLBACK {INSERT OR IGNORE} 0 {} 1 + 12 {} {INSERT OR IGNORE} 0 {} 1 + 13 {} {INSERT OR REPLACE} 0 5 1 + 14 {} {INSERT OR FAIL} 1 {} 1 + 15 {} {INSERT OR ABORT} 1 {} 1 + 16 {} {INSERT OR ROLLBACK} 1 {} {} +} { + if {$t0} {set t1 {NOT NULL constraint failed: t1.c}} + do_test conflict2-5.$i { + if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"} + set r0 [catch {execsql [subst { + DROP TABLE t1; + CREATE TABLE t1(a,b,c NOT NULL $conf1 DEFAULT 5); + DELETE FROM t2; + BEGIN; + INSERT INTO t2 VALUES(1); + $cmd INTO t1 VALUES(1,2,NULL); + }]} r1] + catch {execsql {COMMIT}} + if {!$r0} {set r1 [execsql {SELECT c FROM t1}]} + set r2 [execsql {SELECT x FROM t2}] + list $r0 $r1 $r2 + } [list $t0 $t1 $t2] +} + +do_test conflict2-6.0 { + execsql { + DROP TABLE t2; + CREATE TABLE t2(a,b,c); + INSERT INTO t2 VALUES(1,2,1); + INSERT INTO t2 VALUES(2,3,2); + INSERT INTO t2 VALUES(3,4,1); + INSERT INTO t2 VALUES(4,5,4); + SELECT c FROM t2 ORDER BY b; + CREATE TABLE t3(x); + INSERT INTO t3 VALUES(1); + } +} {1 2 1 4} + +# Six columns of configuration data as follows: +# +# i The reference number of the test +# conf1 The conflict resolution algorithm on the UNIQUE constraint +# cmd An UPDATE command to execute against table t1 +# t0 True if there is an error from $cmd +# t1 Content of "b" column of t1 assuming no error in $cmd +# t2 Content of "x" column of t3 +# t3 Number of temporary files for tables +# t4 Number of temporary files for statement journals +# +# Update: Since temporary table files are now opened lazily, and none +# of the following tests use large quantities of data, t3 is always 0. +# +foreach {i conf1 cmd t0 t1 t2 t3 t4} { + 1 {} UPDATE 1 {6 7 8 9} 1 0 1 + 2 REPLACE UPDATE 0 {7 6 9} 1 0 0 + 3 IGNORE UPDATE 0 {6 7 3 9} 1 0 0 + 4 FAIL UPDATE 1 {6 7 3 4} 1 0 0 + 5 ABORT UPDATE 1 {1 2 3 4} 1 0 1 + 6 ROLLBACK UPDATE 1 {1 2 3 4} 0 0 0 + 7 REPLACE {UPDATE OR IGNORE} 0 {6 7 3 9} 1 0 0 + 8 IGNORE {UPDATE OR REPLACE} 0 {7 6 9} 1 0 1 + 9 FAIL {UPDATE OR IGNORE} 0 {6 7 3 9} 1 0 0 + 10 ABORT {UPDATE OR REPLACE} 0 {7 6 9} 1 0 1 + 11 ROLLBACK {UPDATE OR IGNORE} 0 {6 7 3 9} 1 0 0 + 12 {} {UPDATE OR IGNORE} 0 {6 7 3 9} 1 0 0 + 13 {} {UPDATE OR REPLACE} 0 {7 6 9} 1 0 1 + 14 {} {UPDATE OR FAIL} 1 {6 7 3 4} 1 0 0 + 15 {} {UPDATE OR ABORT} 1 {1 2 3 4} 1 0 1 + 16 {} {UPDATE OR ROLLBACK} 1 {1 2 3 4} 0 0 0 +} { + + # When using in-memory journals, no temporary files are required for + # statement journals. + if {[permutation] == "inmemory_journal"} { set t4 0 } + + if {$t0} {set t1 {UNIQUE constraint failed: t1.a}} + if {[info exists TEMP_STORE] && $TEMP_STORE==3} { + set t3 0 + } else { + set t3 [expr {$t3+$t4}] + } + do_test conflict2-6.$i { + db close + sqlite3 db test.db + if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"} + execsql {pragma temp_store=file} + set ::sqlite_opentemp_count 0 + set r0 [catch {execsql [subst { + DROP TABLE t1; + CREATE TABLE t1(a,b,c, PRIMARY KEY(a) $conf1) WITHOUT rowid; + INSERT INTO t1 SELECT * FROM t2; + UPDATE t3 SET x=0; + BEGIN; + $cmd t3 SET x=1; + $cmd t1 SET b=b*2; + $cmd t1 SET a=c+5; + }]} r1] + catch {execsql {COMMIT}} + if {!$r0} {set r1 [execsql {SELECT a FROM t1 ORDER BY b}]} + set r2 [execsql {SELECT x FROM t3}] + list $r0 $r1 $r2 $::sqlite_opentemp_count + } [list $t0 $t1 $t2 $t3] +} + +# Test to make sure a lot of IGNOREs don't cause a stack overflow +# +do_test conflict2-7.1 { + execsql { + DROP TABLE t1; + DROP TABLE t2; + DROP TABLE t3; + CREATE TABLE t1(a PRIMARY KEY, b) without rowid; + } + for {set i 1} {$i<=50} {incr i} { + execsql "INSERT into t1 values($i,[expr {$i+1}]);" + } + execsql { + SELECT count(*), min(a), max(b) FROM t1; + } +} {50 1 51} +do_test conflict2-7.2 { + execsql { + PRAGMA count_changes=on; + UPDATE OR IGNORE t1 SET a=1000; + } +} {1} +do_test conflict2-7.2.1 { + db changes +} {1} +do_test conflict2-7.3 { + execsql { + SELECT b FROM t1 WHERE a=1000; + } +} {2} +do_test conflict2-7.4 { + execsql { + SELECT count(*) FROM t1; + } +} {50} +do_test conflict2-7.5 { + execsql { + PRAGMA count_changes=on; + UPDATE OR REPLACE t1 SET a=1001; + } +} {50} +do_test conflict2-7.5.1 { + db changes +} {50} +do_test conflict2-7.7 { + execsql { + SELECT count(*) FROM t1; + } +} {1} + +# Update for version 3: A SELECT statement no longer resets the change +# counter (Test result changes from 0 to 50). +do_test conflict2-7.7.1 { + db changes +} {50} + +# Make sure the row count is right for rows that are ignored on +# an insert. +# +do_test conflict2-8.1 { + execsql { + DELETE FROM t1; + INSERT INTO t1 VALUES(1,2); + } + execsql { + INSERT OR IGNORE INTO t1 VALUES(2,3); + } +} {1} +do_test conflict2-8.1.1 { + db changes +} {1} +do_test conflict2-8.2 { + execsql { + INSERT OR IGNORE INTO t1 VALUES(2,4); + } +} {0} +do_test conflict2-8.2.1 { + db changes +} {0} +do_test conflict2-8.3 { + execsql { + INSERT OR REPLACE INTO t1 VALUES(2,4); + } +} {1} +do_test conflict2-8.3.1 { + db changes +} {1} +do_test conflict2-8.4 { + execsql { + INSERT OR IGNORE INTO t1 SELECT * FROM t1; + } +} {0} +do_test conflict2-8.4.1 { + db changes +} {0} +do_test conflict2-8.5 { + execsql { + INSERT OR IGNORE INTO t1 SELECT a+2,b+2 FROM t1; + } +} {2} +do_test conflict2-8.5.1 { + db changes +} {2} +do_test conflict2-8.6 { + execsql { + INSERT OR IGNORE INTO t1 SELECT a+3,b+3 FROM t1; + } +} {3} +do_test conflict2-8.6.1 { + db changes +} {3} + +integrity_check conflict2-8.99 + +do_test conflict2-9.1 { + execsql { + PRAGMA count_changes=0; + CREATE TABLE t2( + a INTEGER PRIMARY KEY ON CONFLICT IGNORE, + b INTEGER UNIQUE ON CONFLICT FAIL, + c INTEGER UNIQUE ON CONFLICT REPLACE, + d INTEGER UNIQUE ON CONFLICT ABORT, + e INTEGER UNIQUE ON CONFLICT ROLLBACK + ) WITHOUT rowid; + CREATE TABLE t3(x); + INSERT INTO t3 VALUES(1); + SELECT * FROM t3; + } +} {1} +do_test conflict2-9.2 { + catchsql { + INSERT INTO t2 VALUES(1,1,1,1,1); + INSERT INTO t2 VALUES(2,2,2,2,2); + SELECT * FROM t2; + } +} {0 {1 1 1 1 1 2 2 2 2 2}} +do_test conflict2-9.3 { + catchsql { + INSERT INTO t2 VALUES(1,3,3,3,3); + SELECT * FROM t2; + } +} {0 {1 1 1 1 1 2 2 2 2 2}} +do_test conflict2-9.4 { + catchsql { + UPDATE t2 SET a=a+1 WHERE a=1; + SELECT * FROM t2; + } +} {0 {1 1 1 1 1 2 2 2 2 2}} +do_test conflict2-9.5 { + catchsql { + INSERT INTO t2 VALUES(3,1,3,3,3); + } +} {1 {UNIQUE constraint failed: t2.b}} +do_test conflict2-9.5b { + db eval {SELECT * FROM t2;} +} {1 1 1 1 1 2 2 2 2 2} +do_test conflict2-9.6 { + catchsql { + UPDATE t2 SET b=b+1 WHERE b=1; + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.b}} +do_test conflict2-9.6b { + db eval {SELECT * FROM t2;} +} {1 1 1 1 1 2 2 2 2 2} +do_test conflict2-9.7 { + catchsql { + BEGIN; + UPDATE t3 SET x=x+1; + INSERT INTO t2 VALUES(3,1,3,3,3); + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.b}} +do_test conflict2-9.8 { + execsql {COMMIT} + execsql {SELECT * FROM t3} +} {2} +do_test conflict2-9.9 { + catchsql { + BEGIN; + UPDATE t3 SET x=x+1; + UPDATE t2 SET b=b+1 WHERE b=1; + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.b}} +do_test conflict2-9.10 { + execsql {COMMIT} + execsql {SELECT * FROM t3} +} {3} +do_test conflict2-9.11 { + catchsql { + INSERT INTO t2 VALUES(3,3,3,1,3); + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.d}} +do_test conflict2-9.12 { + catchsql { + UPDATE t2 SET d=d+1 WHERE d=1; + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.d}} +do_test conflict2-9.13 { + catchsql { + BEGIN; + UPDATE t3 SET x=x+1; + INSERT INTO t2 VALUES(3,3,3,1,3); + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.d}} +do_test conflict2-9.14 { + execsql {COMMIT} + execsql {SELECT * FROM t3} +} {4} +do_test conflict2-9.15 { + catchsql { + BEGIN; + UPDATE t3 SET x=x+1; + UPDATE t2 SET d=d+1 WHERE d=1; + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.d}} +do_test conflict2-9.16 { + execsql {COMMIT} + execsql {SELECT * FROM t3} +} {5} +do_test conflict2-9.17 { + catchsql { + INSERT INTO t2 VALUES(3,3,3,3,1); + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.e}} +do_test conflict2-9.18 { + catchsql { + UPDATE t2 SET e=e+1 WHERE e=1; + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.e}} +do_test conflict2-9.19 { + catchsql { + BEGIN; + UPDATE t3 SET x=x+1; + INSERT INTO t2 VALUES(3,3,3,3,1); + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.e}} +verify_ex_errcode conflict2-9.21b SQLITE_CONSTRAINT_UNIQUE +do_test conflict2-9.20 { + catch {execsql {COMMIT}} + execsql {SELECT * FROM t3} +} {5} +do_test conflict2-9.21 { + catchsql { + BEGIN; + UPDATE t3 SET x=x+1; + UPDATE t2 SET e=e+1 WHERE e=1; + SELECT * FROM t2; + } +} {1 {UNIQUE constraint failed: t2.e}} +verify_ex_errcode conflict2-9.21b SQLITE_CONSTRAINT_UNIQUE +do_test conflict2-9.22 { + catch {execsql {COMMIT}} + execsql {SELECT * FROM t3} +} {5} +do_test conflict2-9.23 { + catchsql { + INSERT INTO t2 VALUES(3,3,1,3,3); + SELECT * FROM t2; + } +} {0 {2 2 2 2 2 3 3 1 3 3}} +do_test conflict2-9.24 { + catchsql { + UPDATE t2 SET c=c-1 WHERE c=2; + SELECT * FROM t2; + } +} {0 {2 2 1 2 2}} +do_test conflict2-9.25 { + catchsql { + BEGIN; + UPDATE t3 SET x=x+1; + INSERT INTO t2 VALUES(3,3,1,3,3); + SELECT * FROM t2; + } +} {0 {3 3 1 3 3}} +do_test conflict2-9.26 { + catch {execsql {COMMIT}} + execsql {SELECT * FROM t3} +} {6} + +do_test conflict2-10.1 { + catchsql { + DELETE FROM t1; + BEGIN; + INSERT OR ROLLBACK INTO t1 VALUES(1,2); + INSERT OR ROLLBACK INTO t1 VALUES(1,3); + COMMIT; + } + execsql {SELECT * FROM t1} +} {} +do_test conflict2-10.2 { + catchsql { + CREATE TABLE t4(x); + CREATE UNIQUE INDEX t4x ON t4(x); + BEGIN; + INSERT OR ROLLBACK INTO t4 VALUES(1); + INSERT OR ROLLBACK INTO t4 VALUES(1); + COMMIT; + } + execsql {SELECT * FROM t4} +} {} + +# Ticket #1171. Make sure statement rollbacks do not +# damage the database. +# +do_test conflict2-11.1 { + execsql { + -- Create a database object (pages 2, 3 of the file) + BEGIN; + CREATE TABLE abc(a PRIMARY KEY, b, c) WITHOUT rowid; + INSERT INTO abc VALUES(1, 2, 3); + INSERT INTO abc VALUES(4, 5, 6); + INSERT INTO abc VALUES(7, 8, 9); + COMMIT; + } + + + # Set a small cache size so that changes will spill into + # the database file. + execsql { + PRAGMA cache_size = 10; + } + + # Make lots of changes. Because of the small cache, some + # (most?) of these changes will spill into the disk file. + # In other words, some of the changes will not be held in + # cache. + # + execsql { + BEGIN; + -- Make sure the pager is in EXCLUSIVE state. + CREATE TABLE def(d, e, f); + INSERT INTO def VALUES + ('xxxxxxxxxxxxxxx', 'yyyyyyyyyyyyyyyy', 'zzzzzzzzzzzzzzzz'); + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + DELETE FROM abc WHERE a = 4; + } + + # Execute a statement that does a statement rollback due to + # a constraint failure. + # + catchsql { + INSERT INTO abc SELECT 10, 20, 30 FROM def; + } + + # Rollback the database. Verify that the state of the ABC table + # is unchanged from the beginning of the transaction. In other words, + # make sure the DELETE on table ABC that occurred within the transaction + # had no effect. + # + execsql { + ROLLBACK; + SELECT * FROM abc; + } +} {1 2 3 4 5 6 7 8 9} +integrity_check conflict2-11.2 + +# Repeat test conflict2-11.1 but this time commit. +# +do_test conflict2-11.3 { + execsql { + BEGIN; + -- Make sure the pager is in EXCLUSIVE state. + UPDATE abc SET a=a+1; + CREATE TABLE def(d, e, f); + INSERT INTO def VALUES + ('xxxxxxxxxxxxxxx', 'yyyyyyyyyyyyyyyy', 'zzzzzzzzzzzzzzzz'); + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + DELETE FROM abc WHERE a = 4; + } + catchsql { + INSERT INTO abc SELECT 10, 20, 30 FROM def; + } + execsql { + ROLLBACK; + SELECT * FROM abc; + } +} {1 2 3 4 5 6 7 8 9} +# Repeat test conflict2-11.1 but this time commit. +# +do_test conflict2-11.5 { + execsql { + BEGIN; + -- Make sure the pager is in EXCLUSIVE state. + CREATE TABLE def(d, e, f); + INSERT INTO def VALUES + ('xxxxxxxxxxxxxxx', 'yyyyyyyyyyyyyyyy', 'zzzzzzzzzzzzzzzz'); + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + INSERT INTO def SELECT * FROM def; + DELETE FROM abc WHERE a = 4; + } + catchsql { + INSERT INTO abc SELECT 10, 20, 30 FROM def; + } + execsql { + COMMIT; + SELECT * FROM abc; + } +} {1 2 3 7 8 9} +integrity_check conflict2-11.6 + +# Make sure UPDATE OR REPLACE works on tables that have only +# an INTEGER PRIMARY KEY. +# +do_test conflict2-12.1 { + execsql { + CREATE TABLE t5(a INTEGER PRIMARY KEY, b text) WITHOUT rowid; + INSERT INTO t5 VALUES(1,'one'); + INSERT INTO t5 VALUES(2,'two'); + SELECT * FROM t5 + } +} {1 one 2 two} +do_test conflict2-12.2 { + execsql { + UPDATE OR IGNORE t5 SET a=a+1 WHERE a=1; + SELECT * FROM t5; + } +} {1 one 2 two} +do_test conflict2-12.3 { + catchsql { + UPDATE t5 SET a=a+1 WHERE a=1; + } +} {1 {UNIQUE constraint failed: t5.a}} +verify_ex_errcode conflict2-12.3b SQLITE_CONSTRAINT_PRIMARYKEY +do_test conflict2-12.4 { + execsql { + UPDATE OR REPLACE t5 SET a=a+1 WHERE a=1; + SELECT * FROM t5; + } +} {2 one} + + +# Ticket [c38baa3d969eab7946dc50ba9d9b4f0057a19437] +# REPLACE works like ABORT on a CHECK constraint. +# +do_test conflict2-13.1 { + execsql { + CREATE TABLE t13(a PRIMARY KEY CHECK(a!=2)) WITHOUT rowid; + BEGIN; + REPLACE INTO t13 VALUES(1); + } + catchsql { + REPLACE INTO t13 VALUES(2); + } +} {1 {CHECK constraint failed: t13}} +verify_ex_errcode conflict2-13.1b SQLITE_CONSTRAINT_CHECK +do_test conflict2-13.2 { + execsql { + REPLACE INTO t13 VALUES(3); + COMMIT; + SELECT * FROM t13; + } +} {1 3} + +# Test for an unreleased bug in the REPLACE conflict resolution +# discovered on 2013-11-09. +# +do_execsql_test conflict2-14.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1( + x TEXT PRIMARY KEY NOT NULL, + y TEXT NOT NULL, + z INTEGER + ); + INSERT INTO t1 VALUES('alpha','beta',1); + CREATE UNIQUE INDEX t1xy ON t1(x,y); + REPLACE INTO t1(x,y,z) VALUES('alpha','gamma',1); + PRAGMA integrity_check; + SELECT x,y FROM t1 INDEXED BY t1xy; + SELECT x,y,z FROM t1 NOT INDEXED; +} {ok alpha gamma alpha gamma 1} +do_execsql_test conflict2-14.2 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1( + x TEXT PRIMARY KEY NOT NULL, + y TEXT NOT NULL, + z INTEGER + ) WITHOUT ROWID; + INSERT INTO t1 VALUES('alpha','beta',1); + CREATE UNIQUE INDEX t1xy ON t1(x,y); + REPLACE INTO t1(x,y,z) VALUES('alpha','gamma',1); + PRAGMA integrity_check; + SELECT x,y FROM t1 INDEXED BY t1xy; + SELECT x,y,z FROM t1 NOT INDEXED; +} {ok alpha gamma alpha gamma 1} + + + +finish_test diff --git a/test/conflict3.test b/test/conflict3.test new file mode 100644 index 0000000..b51a55e --- /dev/null +++ b/test/conflict3.test @@ -0,0 +1,356 @@ +# 2013-11-05 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests for the conflict resolution extension +# to SQLite. +# +# This file focuses on making sure that combinations of REPLACE, +# IGNORE, and FAIL conflict resolution play well together. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !conflict { + finish_test + return +} + +do_execsql_test conflict-1.1 { + CREATE TABLE t1( + a INTEGER PRIMARY KEY ON CONFLICT REPLACE, + b UNIQUE ON CONFLICT IGNORE, + c UNIQUE ON CONFLICT FAIL + ); + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-1.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-1.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-1.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Replete the tests above, but this time on a table non-INTEGER primary key. +# +do_execsql_test conflict-2.1 { + DROP TABLE t1; + CREATE TABLE t1( + a INT PRIMARY KEY ON CONFLICT REPLACE, + b UNIQUE ON CONFLICT IGNORE, + c UNIQUE ON CONFLICT FAIL + ); + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-2.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-2.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-2.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Replete again on a WITHOUT ROWID table. +# +do_execsql_test conflict-3.1 { + DROP TABLE t1; + CREATE TABLE t1( + a INT PRIMARY KEY ON CONFLICT REPLACE, + b UNIQUE ON CONFLICT IGNORE, + c UNIQUE ON CONFLICT FAIL + ) WITHOUT ROWID; + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-3.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-3.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-3.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Arrange the table rows in a different order and repeat. +# +do_execsql_test conflict-4.1 { + DROP TABLE t1; + CREATE TABLE t1( + b UNIQUE ON CONFLICT IGNORE, + c UNIQUE ON CONFLICT FAIL, + a INT PRIMARY KEY ON CONFLICT REPLACE + ) WITHOUT ROWID; + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-4.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-4.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-4.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Arrange the table rows in a different order and repeat. +# +do_execsql_test conflict-5.1 { + DROP TABLE t1; + CREATE TABLE t1( + b UNIQUE ON CONFLICT IGNORE, + a INT PRIMARY KEY ON CONFLICT REPLACE, + c UNIQUE ON CONFLICT FAIL + ); + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-5.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-5.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-5.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Arrange the table rows in a different order and repeat. +# +do_execsql_test conflict-6.1 { + DROP TABLE t1; + CREATE TABLE t1( + c UNIQUE ON CONFLICT FAIL, + a INT PRIMARY KEY ON CONFLICT REPLACE, + b UNIQUE ON CONFLICT IGNORE + ); + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-6.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-6.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-6.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Change which column is the PRIMARY KEY +# +do_execsql_test conflict-7.1 { + DROP TABLE t1; + CREATE TABLE t1( + a UNIQUE ON CONFLICT REPLACE, + b INTEGER PRIMARY KEY ON CONFLICT IGNORE, + c UNIQUE ON CONFLICT FAIL + ); + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-7.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-7.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-7.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Change which column is the PRIMARY KEY +# +do_execsql_test conflict-8.1 { + DROP TABLE t1; + CREATE TABLE t1( + a UNIQUE ON CONFLICT REPLACE, + b INT PRIMARY KEY ON CONFLICT IGNORE, + c UNIQUE ON CONFLICT FAIL + ); + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-8.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-8.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-8.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Change which column is the PRIMARY KEY +# +do_execsql_test conflict-9.1 { + DROP TABLE t1; + CREATE TABLE t1( + a UNIQUE ON CONFLICT REPLACE, + b INT PRIMARY KEY ON CONFLICT IGNORE, + c UNIQUE ON CONFLICT FAIL + ) WITHOUT ROWID; + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-9.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-9.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-9.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Change which column is the PRIMARY KEY +# +do_execsql_test conflict-10.1 { + DROP TABLE t1; + CREATE TABLE t1( + a UNIQUE ON CONFLICT REPLACE, + b UNIQUE ON CONFLICT IGNORE, + c INTEGER PRIMARY KEY ON CONFLICT FAIL + ); + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-10.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-10.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-10.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + +# Change which column is the PRIMARY KEY +# +do_execsql_test conflict-11.1 { + DROP TABLE t1; + CREATE TABLE t1( + a UNIQUE ON CONFLICT REPLACE, + b UNIQUE ON CONFLICT IGNORE, + c PRIMARY KEY ON CONFLICT FAIL + ) WITHOUT ROWID; + INSERT INTO t1(a,b,c) VALUES(1,2,3), (2,3,4); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert a row that conflicts on column B. The insert should be ignored. +# +do_execsql_test conflict-11.2 { + INSERT INTO t1(a,b,c) VALUES(3,2,5); + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4} + +# Insert two rows where the second conflicts on C. The first row show go +# and and then there should be a constraint error. +# +do_test conflict-11.3 { + catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);} +} {1 {UNIQUE constraint failed: t1.c}} +do_execsql_test conflict-11.4 { + SELECT a,b,c FROM t1 ORDER BY a; +} {1 2 3 2 3 4 4 5 6} + + +finish_test diff --git a/test/contrib01.test b/test/contrib01.test new file mode 100644 index 0000000..43ea47c --- /dev/null +++ b/test/contrib01.test @@ -0,0 +1,90 @@ +# 2013-06-05 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file contains test cases that were contributed on the sqlite-users +# mailing list on 2013-06-05 by Mi Chen at mi.chen@echostar.com. +# +# At the time it was contributed, this test failed on trunk, but +# worked on the NGQP. + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Build some test data +# +do_test contrib01-1.0 { + db eval { + CREATE TABLE T1 (B INTEGER NOT NULL, + C INTEGER NOT NULL, + D INTEGER NOT NULL, + E INTEGER NOT NULL, + F INTEGER NOT NULL, + G INTEGER NOT NULL, + H INTEGER NOT NULL, + PRIMARY KEY (B, C, D)); + + CREATE TABLE T2 (A INTEGER NOT NULL, + B INTEGER NOT NULL, + C INTEGER NOT NULL, + PRIMARY KEY (A, B, C)); + + INSERT INTO T2(A, B, C) VALUES(702118,16183,15527); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15560); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15561); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15563); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15564); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15566); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15567); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15569); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15612); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15613); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15638); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15681); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15682); + + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15527,6,0,5,5,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15560,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15561,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15563,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15564,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15566,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15567,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15569,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15612,6,0,5,5,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15613,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15638,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15681,6,0,5,5,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15682,6,0,5,2,0); + } +} {} +do_test contrib01-1.1 { + db eval { + SELECT T2.A, T2.B, T1.D, T1.E, T1.F, T1.G, T1.H, MAX(T1.C), '^' + FROM T1, T2 + WHERE T1.B = T2.B + AND T1.C = T2.C + GROUP BY T2.A, T2.B, T1.D, T1.E, T1.F, T1.G, T1.H + ORDER BY +max(t1.c); + } +} {702118 16183 6 0 5 5 0 15681 ^ 702118 16183 6 0 5 2 0 15682 ^} +do_test contrib01-1.2 { + db eval { + SELECT T2.A, T2.B, T1.D, T1.E, T1.F, T1.G, T1.H, MAX(T1.C), '^' + FROM T1, T2 + WHERE T1.B = T2.B + AND T1.C = T2.C + GROUP BY T2.A, T2.B, T1.F, T1.D, T1.E, T1.G, T1.H + ORDER BY +max(t1.c); + } +} {702118 16183 6 0 5 5 0 15681 ^ 702118 16183 6 0 5 2 0 15682 ^} + +finish_test diff --git a/test/corrupt.test b/test/corrupt.test index 09f3c5b..3e49a9f 100644 --- a/test/corrupt.test +++ b/test/corrupt.test @@ -25,6 +25,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # Construct a large database for testing. # do_test corrupt-1.1 { diff --git a/test/corrupt2.test b/test/corrupt2.test index 744a76e..805a614 100644 --- a/test/corrupt2.test +++ b/test/corrupt2.test @@ -23,6 +23,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + set presql "" catch { set presql "$::G(perm:presql);" } unset -nocomplain ::G(perm:presql) diff --git a/test/corrupt3.test b/test/corrupt3.test index a382722..436a466 100644 --- a/test/corrupt3.test +++ b/test/corrupt3.test @@ -23,6 +23,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas||direct_read { diff --git a/test/corrupt4.test b/test/corrupt4.test index 1906113..24db60f 100644 --- a/test/corrupt4.test +++ b/test/corrupt4.test @@ -23,6 +23,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas { diff --git a/test/corrupt5.test b/test/corrupt5.test index dca06e5..3f50996 100644 --- a/test/corrupt5.test +++ b/test/corrupt5.test @@ -19,6 +19,10 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +# These tests deal with corrupt database files +# +database_may_be_corrupt + # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas { diff --git a/test/corrupt6.test b/test/corrupt6.test index c0dcedf..7d90c4a 100644 --- a/test/corrupt6.test +++ b/test/corrupt6.test @@ -24,6 +24,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas { diff --git a/test/corrupt7.test b/test/corrupt7.test index ad56656..db92cf1 100644 --- a/test/corrupt7.test +++ b/test/corrupt7.test @@ -24,6 +24,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas { diff --git a/test/corrupt8.test b/test/corrupt8.test index 012beb5..d7bceba 100644 --- a/test/corrupt8.test +++ b/test/corrupt8.test @@ -24,6 +24,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas||!autovacuum { diff --git a/test/corrupt9.test b/test/corrupt9.test index f199452..bb37758 100644 --- a/test/corrupt9.test +++ b/test/corrupt9.test @@ -24,6 +24,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas { diff --git a/test/corruptA.test b/test/corruptA.test index 8b76d3a..bb9912b 100644 --- a/test/corruptA.test +++ b/test/corruptA.test @@ -24,6 +24,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # Create a database to work with. # diff --git a/test/corruptB.test b/test/corruptB.test index 0ff2d6e..c51cb57 100644 --- a/test/corruptB.test +++ b/test/corruptB.test @@ -30,6 +30,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + do_test corruptB-1.1 { execsql { diff --git a/test/corruptC.test b/test/corruptC.test index 34e81a1..adf6f44 100644 --- a/test/corruptC.test +++ b/test/corruptC.test @@ -27,6 +27,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # Construct a compact, dense database for testing. # do_test corruptC-1.1 { @@ -202,6 +206,10 @@ do_test corruptC-2.8 { } {1 {database disk image is malformed}} # corruption (seed 170434) +# +# UPDATE: Prior to 3.8.2, this used to return SQLITE_CORRUPT. It no longer +# does. That is Ok, the point of these tests is to verify that no buffer +# overruns or overreads can be caused by corrupt databases. do_test corruptC-2.9 { db close forcecopy test.bu test.db @@ -211,7 +219,7 @@ do_test corruptC-2.9 { sqlite3 db test.db catchsql {BEGIN; DELETE FROM t1 WHERE x>13; ROLLBACK;} -} {1 {database disk image is malformed}} +} {0 {}} # corruption (seed 186504) do_test corruptC-2.10 { diff --git a/test/corruptD.test b/test/corruptD.test index 2423cd4..6347458 100644 --- a/test/corruptD.test +++ b/test/corruptD.test @@ -19,6 +19,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + #-------------------------------------------------------------------------- # OVERVIEW # diff --git a/test/corruptE.test b/test/corruptE.test index 48292ab..4d5b5db 100644 --- a/test/corruptE.test +++ b/test/corruptE.test @@ -24,6 +24,10 @@ source $testdir/tester.tcl # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + # Do not run the tests in this file if ENABLE_OVERSIZE_CELL_CHECK is on. # ifcapable oversize_cell_check { diff --git a/test/corruptF.test b/test/corruptF.test index 33eef39..8c4fd84 100644 --- a/test/corruptF.test +++ b/test/corruptF.test @@ -19,6 +19,10 @@ set testprefix corruptF # do_not_use_codec +# These tests deal with corrupt database files +# +database_may_be_corrupt + proc str {i} { format %08d $i } # Create a 6 page database containing a single table - t1. Table t1 @@ -147,4 +151,3 @@ for {set i 127} {$i >= 0} {incr i -1} { } finish_test - diff --git a/test/corruptG.test b/test/corruptG.test new file mode 100644 index 0000000..af920ed --- /dev/null +++ b/test/corruptG.test @@ -0,0 +1,76 @@ +# 2013-08-01 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix corruptG + +# Do not use a codec for tests in this file, as the database file is +# manipulated directly using tcl scripts (using the [hexio_write] command). +# +do_not_use_codec + +# These tests deal with corrupt database files +# +database_may_be_corrupt + +# Create a simple database with a single entry. Then corrupt the +# header-size varint on the index payload so that it maps into a +# negative number. Try to use the database. +# + +do_execsql_test 1.1 { + PRAGMA page_size=512; + CREATE TABLE t1(a,b,c); + INSERT INTO t1(rowid,a,b,c) VALUES(52,'abc','xyz','123'); + CREATE INDEX t1abc ON t1(a,b,c); +} + +set idxroot [db one {SELECT rootpage FROM sqlite_master WHERE name = 't1abc'}] + +# Corrupt the file +db close +hexio_write test.db [expr {$idxroot*512 - 15}] 888080807f +sqlite3 db test.db + +# Try to use the file. +do_test 1.2 { + catchsql { + SELECT c FROM t1 WHERE a>'abc'; + } +} {1 {database disk image is malformed}} +do_test 1.3 { + catchsql { + PRAGMA integrity_check + } +} {1 {database disk image is malformed}} +do_test 1.4 { + catchsql { + SELECT c FROM t1 ORDER BY a; + } +} {1 {database disk image is malformed}} + +# Corrupt the same file in a slightly different way. Make the record header +# sane, but corrupt one of the serial_type value to indicate a huge payload +# such that the payload begins in allocated space but overflows the buffer. +# +db close +hexio_write test.db [expr {$idxroot*512-15}] 0513ff7f01 +sqlite3 db test.db + +do_test 2.1 { + catchsql { + SELECT rowid FROM t1 WHERE a='abc' and b='xyz123456789XYZ'; + } +} {1 {database disk image is malformed}} + +finish_test diff --git a/test/corruptH.test b/test/corruptH.test new file mode 100644 index 0000000..ee2bb1e --- /dev/null +++ b/test/corruptH.test @@ -0,0 +1,178 @@ +# 2014-01-20 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix corruptH + +# Do not use a codec for tests in this file, as the database file is +# manipulated directly using tcl scripts (using the [hexio_write] command). +# +do_not_use_codec +database_may_be_corrupt + +# The corruption migrations tested by the code in this file are not detected +# mmap mode. +# +# The reason is that in mmap mode, the different queries may use different +# PgHdr objects for the same page (same data, but different PgHdr container +# objects). And so the corruption is not detected. +# +if {[permutation]=="mmap"} { + finish_test + return +} + +# Initialize the database. +# +do_execsql_test 1.1 { + PRAGMA page_size=1024; + + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + INSERT INTO t1 VALUES(1, 'one'); + INSERT INTO t1 VALUES(2, 'two'); + + CREATE TABLE t2(x); + INSERT INTO t2 VALUES(randomblob(200)); + INSERT INTO t2 SELECT randomblob(200) FROM t2; + INSERT INTO t2 SELECT randomblob(200) FROM t2; + INSERT INTO t2 SELECT randomblob(200) FROM t2; + INSERT INTO t2 SELECT randomblob(200) FROM t2; + INSERT INTO t2 SELECT randomblob(200) FROM t2; + INSERT INTO t2 SELECT randomblob(200) FROM t2; +} {} + +# Corrupt the file so that the root page of t1 is also linked into t2 as +# a leaf page. +# +do_test 1.2 { + db eval { SELECT name, rootpage FROM sqlite_master } { + set r($name) $rootpage + } + db close + hexio_write test.db [expr {($r(t2)-1)*1024 + 11}] [format %.2X $r(t1)] + sqlite3 db test.db +} {} + +do_test 1.3 { +breakpoint + db eval { PRAGMA secure_delete=1 } + list [catch { + db eval { SELECT * FROM t1 WHERE a IN (1, 2) } { + db eval { DELETE FROM t2 } + } + } msg] $msg +} {1 {database disk image is malformed}} + +#------------------------------------------------------------------------- +reset_db + +# Initialize the database. +# +do_execsql_test 2.1 { + PRAGMA auto_vacuum=0; + PRAGMA page_size=1024; + + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + INSERT INTO t1 VALUES(1, 'one'); + INSERT INTO t1 VALUES(2, 'two'); + + CREATE TABLE t3(x); + + CREATE TABLE t2(x PRIMARY KEY) WITHOUT ROWID; + INSERT INTO t2 VALUES(randomblob(100)); + + DROP TABLE t3; +} {} + +do_test 2.2 { + db eval { SELECT name, rootpage FROM sqlite_master } { + set r($name) $rootpage + } + db close + set fl [hexio_get_int [hexio_read test.db 32 4]] + + hexio_write test.db [expr {($fl-1) * 1024 + 0}] 00000000 + hexio_write test.db [expr {($fl-1) * 1024 + 4}] 00000001 + hexio_write test.db [expr {($fl-1) * 1024 + 8}] [format %.8X $r(t1)] + hexio_write test.db 36 00000002 + + sqlite3 db test.db +} {} + + +# The trick here is that the root page of the tree scanned by the outer +# query is also currently on the free-list. So while the first seek on +# the table (for a==1) works, by the time the second is attempted The +# "INSERT INTO t2..." statements have recycled the root page of t1 and +# used it as an index leaf. Normally, BtreeMovetoUnpacked() detects +# that the PgHdr object associated with said root page does not match +# the cursor (as it is now marked with PgHdr.intKey==0) and returns +# SQLITE_CORRUPT. +# +set res23 {1 {database disk image is malformed}} +do_test 2.3 { + list [catch { + set res [list] + db eval { SELECT * FROM t1 WHERE a IN (1, 2) } { + db eval { + INSERT INTO t2 SELECT randomblob(100) FROM t2; + INSERT INTO t2 SELECT randomblob(100) FROM t2; + INSERT INTO t2 SELECT randomblob(100) FROM t2; + INSERT INTO t2 SELECT randomblob(100) FROM t2; + INSERT INTO t2 SELECT randomblob(100) FROM t2; + } + lappend res $b + } + set res + } msg] $msg +} $res23 + +#------------------------------------------------------------------------- +reset_db + +# Initialize the database. +# +do_execsql_test 3.1 { + PRAGMA page_size=1024; + + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + INSERT INTO t1 VALUES(1, 'one'); + INSERT INTO t1 VALUES(2, 'two'); + + CREATE TABLE t2(c INTEGER PRAGMA KEY, d); + INSERT INTO t2 VALUES(1, randomblob(1100)); +} {} + +do_test 3.2 { + db eval { SELECT name, rootpage FROM sqlite_master } { + set r($name) $rootpage + } + db close + + hexio_write test.db [expr {($r(t2)-1) * 1024 + 1020}] 00000002 + + sqlite3 db test.db +} {} + +do_test 3.3 { + list [catch { + db eval { SELECT * FROM t1 WHERE a IN (1, 2) } { + db eval { + DELETE FROM t2 WHERE c=1; + } + } + } msg] $msg +} {1 {database disk image is malformed}} + +finish_test + diff --git a/test/corruptI.test b/test/corruptI.test new file mode 100644 index 0000000..41200c5 --- /dev/null +++ b/test/corruptI.test @@ -0,0 +1,105 @@ +# 2014-01-20 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix corruptI + +if {[permutation]=="mmap"} { + finish_test + return +} + +# Do not use a codec for tests in this file, as the database file is +# manipulated directly using tcl scripts (using the [hexio_write] command). +# +do_not_use_codec +database_may_be_corrupt + +# Initialize the database. +# +do_execsql_test 1.1 { + PRAGMA page_size=1024; + PRAGMA auto_vacuum=0; + CREATE TABLE t1(a); + CREATE INDEX i1 ON t1(a); + INSERT INTO t1 VALUES('abcdefghijklmnop'); +} {} +db close + +do_test 1.2 { + set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]] + set off [expr 2*1024 + $offset + 1] + hexio_write test.db $off 7f06 + sqlite3 db test.db + catchsql { SELECT * FROM t1 WHERE a = 10 } +} {0 {}} + +do_test 1.3 { + db close + set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]] + set off [expr 2*1024 + $offset + 1] + hexio_write test.db $off FFFF7f02 + sqlite3 db test.db + catchsql { SELECT * FROM t1 WHERE a = 10 } +} {1 {database disk image is malformed}} + +do_test 2.0 { + execsql { + CREATE TABLE r(x); + INSERT INTO r VALUES('ABCDEFGHIJK'); + CREATE INDEX r1 ON r(x); + } + set pg [db one {SELECT rootpage FROM sqlite_master WHERE name = 'r1'}] +} {5} + +do_test 2.1 { + db close + set offset [hexio_get_int [hexio_read test.db [expr (5-1)*1024 + 8] 2]] + set off [expr (5-1)*1024 + $offset + 1] + hexio_write test.db $off FFFF0004 + sqlite3 db test.db + catchsql { SELECT * FROM r WHERE x >= 10.0 } +} {1 {database disk image is malformed}} + +do_test 2.2 { + catchsql { SELECT * FROM r WHERE x >= 10 } +} {1 {database disk image is malformed}} + +reset_db + +do_execsql_test 3.1 { + PRAGMA page_size = 512; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + WITH s(a, b) AS ( + SELECT 2, 'abcdefghij' + UNION ALL + SELECT a+2, b FROM s WHERe a < 40 + ) + INSERT INTO t1 SELECT * FROM s; +} {} + +do_test 3.2 { + hexio_write test.db [expr 512+3] 0054 + db close + sqlite3 db test.db + execsql { INSERT INTO t1 VALUES(5, 'klmnopqrst') } + execsql { INSERT INTO t1 VALUES(7, 'klmnopqrst') } +} {} + +db close +sqlite3 db test.db +do_catchsql_test 3.2 { + INSERT INTO t1 VALUES(9, 'klmnopqrst'); +} {1 {database disk image is malformed}} + +finish_test diff --git a/test/cost.test b/test/cost.test new file mode 100644 index 0000000..92fff9c --- /dev/null +++ b/test/cost.test @@ -0,0 +1,292 @@ +# 2014-04-26 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix cost + + +do_execsql_test 1.1 { + CREATE TABLE t3(id INTEGER PRIMARY KEY, b NOT NULL); + CREATE TABLE t4(c, d, e); + CREATE UNIQUE INDEX i3 ON t3(b); + CREATE UNIQUE INDEX i4 ON t4(c, d); +} +do_eqp_test 1.2 { + SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d; +} { + 0 0 0 {SCAN TABLE t3 USING COVERING INDEX i3} + 0 1 1 {SEARCH TABLE t4 USING INDEX i4 (c=?)} +} + + +do_execsql_test 2.1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a); +} + +# It is better to use an index for ORDER BY than sort externally, even +# if the index is a non-covering index. +do_eqp_test 2.2 { + SELECT * FROM t1 ORDER BY a; +} { + 0 0 0 {SCAN TABLE t1 USING INDEX i1} +} + +do_execsql_test 3.1 { + CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g); + CREATE INDEX t5b ON t5(b); + CREATE INDEX t5c ON t5(c); + CREATE INDEX t5d ON t5(d); + CREATE INDEX t5e ON t5(e); + CREATE INDEX t5f ON t5(f); + CREATE INDEX t5g ON t5(g); +} + +do_eqp_test 3.2 { + SELECT a FROM t5 + WHERE b IS NULL OR c IS NULL OR d IS NULL + ORDER BY a; +} { + 0 0 0 {SEARCH TABLE t5 USING INDEX t5b (b=?)} + 0 0 0 {SEARCH TABLE t5 USING INDEX t5c (c=?)} + 0 0 0 {SEARCH TABLE t5 USING INDEX t5d (d=?)} + 0 0 0 {USE TEMP B-TREE FOR ORDER BY} +} + +#------------------------------------------------------------------------- +# If there is no likelihood() or stat3 data, SQLite assumes that a closed +# range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint) +# visits 1/64 of the rows in a table. +# +# Note: 1/63 =~ 0.016 +# Note: 1/65 =~ 0.015 +# +reset_db +do_execsql_test 4.1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a); + CREATE INDEX i2 ON t1(b); +} +do_eqp_test 4.2 { + SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?; +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} +} +do_eqp_test 4.3 { + SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?; +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)} +} + + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 5.1 { + CREATE TABLE t2(x, y); + CREATE INDEX t2i1 ON t2(x); +} + +do_eqp_test 5.2 { + SELECT * FROM t2 ORDER BY x, y; +} { + 0 0 0 {SCAN TABLE t2 USING INDEX t2i1} + 0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} +} + +do_eqp_test 5.3 { + SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid; +} { + 0 0 0 {SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?)} + 0 0 0 {USE TEMP B-TREE FOR ORDER BY} +} + +# where7.test, where8.test: +# +do_execsql_test 6.1 { + CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c); + CREATE INDEX t3i1 ON t3(b); + CREATE INDEX t3i2 ON t3(c); +} + +do_eqp_test 6.2 { + SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a +} { + 0 0 0 {SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)} + 0 0 0 {SEARCH TABLE t3 USING INDEX t3i2 (c=?)} + 0 0 0 {USE TEMP B-TREE FOR ORDER BY} +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 7.1 { + CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d,e,f,g); + CREATE INDEX t1b ON t1(b); + CREATE INDEX t1c ON t1(c); + CREATE INDEX t1d ON t1(d); + CREATE INDEX t1e ON t1(e); + CREATE INDEX t1f ON t1(f); + CREATE INDEX t1g ON t1(g); +} + +do_eqp_test 7.2 { + SELECT a FROM t1 + WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL) + ORDER BY a +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)} + 0 0 0 {USE TEMP B-TREE FOR ORDER BY} +} + +do_eqp_test 7.3 { + SELECT rowid FROM t1 + WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) +} { + 0 0 0 {SCAN TABLE t1} +} + +do_eqp_test 7.4 { + SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL +} { + 0 0 0 {SCAN TABLE t1} +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 8.1 { + CREATE TABLE composer( + cid INTEGER PRIMARY KEY, + cname TEXT + ); + CREATE TABLE album( + aid INTEGER PRIMARY KEY, + aname TEXT + ); + CREATE TABLE track( + tid INTEGER PRIMARY KEY, + cid INTEGER REFERENCES composer, + aid INTEGER REFERENCES album, + title TEXT + ); + CREATE INDEX track_i1 ON track(cid); + CREATE INDEX track_i2 ON track(aid); +} + +do_eqp_test 8.2 { + SELECT DISTINCT aname + FROM album, composer, track + WHERE cname LIKE '%bach%' + AND unlikely(composer.cid=track.cid) + AND unlikely(album.aid=track.aid); +} { + 0 0 2 {SCAN TABLE track} + 0 1 0 {SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?)} + 0 2 1 {SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?)} + 0 0 0 {USE TEMP B-TREE FOR DISTINCT} +} + +#------------------------------------------------------------------------- +# +do_execsql_test 9.1 { + CREATE TABLE t1( + a,b,c,d,e, f,g,h,i,j, + k,l,m,n,o, p,q,r,s,t + ); + CREATE INDEX i1 ON t1(k,l,m,n,o,p,q,r,s,t); +} +do_test 9.2 { + for {set i 0} {$i < 100} {incr i} { + execsql { INSERT INTO t1 DEFAULT VALUES } + } + execsql { + ANALYZE; + CREATE INDEX i2 ON t1(a,b,c,d,e,f,g,h,i,j); + } +} {} + +set L [list a=? b=? c=? d=? e=? f=? g=? h=? i=? j=?] +foreach {tn nTerm nRow} { + 1 1 10 + 2 2 9 + 3 3 8 + 4 4 7 + 5 5 6 + 6 6 5 + 7 7 5 + 8 8 5 + 9 9 5 + 10 10 5 +} { + set w [join [lrange $L 0 [expr $nTerm-1]] " AND "] + set p1 [expr ($nRow-1) / 100.0] + set p2 [expr ($nRow+1) / 100.0] + + set sql1 "SELECT * FROM t1 WHERE likelihood(k=?, $p1) AND $w" + set sql2 "SELECT * FROM t1 WHERE likelihood(k=?, $p2) AND $w" + + do_eqp_test 9.3.$tn.1 $sql1 {/INDEX i1/} + do_eqp_test 9.3.$tn.2 $sql2 {/INDEX i2/} +} + + +#------------------------------------------------------------------------- +# + +ifcapable stat4 { + do_execsql_test 10.1 { + CREATE TABLE t6(a, b, c); + CREATE INDEX t6i1 ON t6(a, b); + CREATE INDEX t6i2 ON t6(c); + } + + do_test 10.2 { + for {set i 0} {$i < 16} {incr i} { + execsql { INSERT INTO t6 VALUES($i%4, 'xyz', $i%8) } + } + execsql ANALYZE + } {} + + do_eqp_test 10.3 { + SELECT rowid FROM t6 WHERE a=0 AND c=0 + } { + 0 0 0 {SEARCH TABLE t6 USING INDEX t6i2 (c=?)} + } + + do_eqp_test 10.4 { + SELECT rowid FROM t6 WHERE a=0 AND b='xyz' AND c=0 + } { + 0 0 0 {SEARCH TABLE t6 USING INDEX t6i2 (c=?)} + } + + do_eqp_test 10.5 { + SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND c=0 + } { + 0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=?)} + } + + do_eqp_test 10.6 { + SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND b='xyz' AND c=0 + } { + 0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=? AND b=?)} + } +} + +finish_test + + + diff --git a/test/count.test b/test/count.test index fbdd13b..3461e49 100644 --- a/test/count.test +++ b/test/count.test @@ -1,4 +1,4 @@ -# 2009 February 24 +# 2009-02-24 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: @@ -11,7 +11,6 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing "SELECT count(*)" statements. # -# $Id: count.test,v 1.6 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -24,8 +23,6 @@ source $testdir/tester.tcl # tables and indexes. Test both when they contain 0 entries, # when all entries are on the root page, and when the b-tree # forms a structure 2 and 3 levels deep. -# -# count-2.*: Test that # # @@ -188,5 +185,10 @@ do_test count-4.3 { } } {1} +do_execsql_test count-5.1 { + CREATE TABLE t5(a TEXT PRIMARY KEY, b VARCHAR(50)) WITHOUT ROWID; + INSERT INTO t5 VALUES('bison','jazz'); + SELECT count(*) FROM t5; +} {1} finish_test diff --git a/test/crash8.test b/test/crash8.test index 8bc2586..930834a 100644 --- a/test/crash8.test +++ b/test/crash8.test @@ -341,62 +341,68 @@ ifcapable pragma { } {jkl} } -for {set i 1} {$i < 10} {incr i} { - catch { db close } - forcedelete test.db test.db-journal - sqlite3 db test.db - do_test crash8-5.$i.1 { - execsql { - CREATE TABLE t1(x PRIMARY KEY); - INSERT INTO t1 VALUES(randomblob(900)); - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 rows */ - } - crashsql -file test.db -delay [expr ($::i%2) + 1] { - PRAGMA cache_size = 10; - BEGIN; - UPDATE t1 SET x = randomblob(900); - ROLLBACK; - INSERT INTO t1 VALUES(randomblob(900)); - } - execsql { PRAGMA integrity_check } - } {ok} +# +# Since the following tests (crash8-5.*) rely upon being able +# to copy a file while open, they will not work on Windows. +# +if {$::tcl_platform(platform)=="unix"} { + for {set i 1} {$i < 10} {incr i} { + catch { db close } + forcedelete test.db test.db-journal + sqlite3 db test.db + do_test crash8-5.$i.1 { + execsql { + CREATE TABLE t1(x PRIMARY KEY); + INSERT INTO t1 VALUES(randomblob(900)); + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 rows */ + } + crashsql -file test.db -delay [expr ($::i%2) + 1] { + PRAGMA cache_size = 10; + BEGIN; + UPDATE t1 SET x = randomblob(900); + ROLLBACK; + INSERT INTO t1 VALUES(randomblob(900)); + } + execsql { PRAGMA integrity_check } + } {ok} - catch { db close } - forcedelete test.db test.db-journal - sqlite3 db test.db - do_test crash8-5.$i.2 { - execsql { - PRAGMA cache_size = 10; - CREATE TABLE t1(x PRIMARY KEY); - INSERT INTO t1 VALUES(randomblob(900)); - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; - INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 rows */ - BEGIN; - UPDATE t1 SET x = randomblob(900); - } - forcedelete testX.db testX.db-journal testX.db-wal - forcecopy test.db testX.db - forcecopy test.db-journal testX.db-journal - db close - - crashsql -file test.db -delay [expr ($::i%2) + 1] { - SELECT * FROM sqlite_master; - INSERT INTO t1 VALUES(randomblob(900)); - } - - sqlite3 db2 testX.db - execsql { PRAGMA integrity_check } db2 - } {ok} + catch { db close } + forcedelete test.db test.db-journal + sqlite3 db test.db + do_test crash8-5.$i.2 { + execsql { + PRAGMA cache_size = 10; + CREATE TABLE t1(x PRIMARY KEY); + INSERT INTO t1 VALUES(randomblob(900)); + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; + INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 rows */ + BEGIN; + UPDATE t1 SET x = randomblob(900); + } + forcedelete testX.db testX.db-journal testX.db-wal + forcecopy test.db testX.db + forcecopy test.db-journal testX.db-journal + db close + + crashsql -file test.db -delay [expr ($::i%2) + 1] { + SELECT * FROM sqlite_master; + INSERT INTO t1 VALUES(randomblob(900)); + } + + sqlite3 db2 testX.db + execsql { PRAGMA integrity_check } db2 + } {ok} + } + catch {db2 close} } -catch {db2 close} finish_test diff --git a/test/crypto.test b/test/crypto.test index 8a58fe0..629be5d 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -4,8 +4,6 @@ # http://zetetic.net # # Copyright (c) 2009, ZETETIC LLC -# All rights reserved. -# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright @@ -44,6 +42,7 @@ file delete -force test4.db set testdir [file dirname $argv0] source $testdir/tester.tcl +set old_pending_byte [sqlite3_test_control_pending_byte 0x40000000] # If the library is not compiled with has_codec support then # skip all tests in this file. @@ -88,6 +87,21 @@ proc if_built_with_commoncrypto {name cmd expected} { } } +proc cmpFilesChunked {file1 file2 {chunksize 16384}} { + set f1 [open $file1]; fconfigure $f1 -translation binary + set f2 [open $file2]; fconfigure $f2 -translation binary + while {1} { + set d1 [read $f1 $chunksize] + set d2 [read $f2 $chunksize] + set diff [string compare $d1 $d2] + if {$diff != 0 || [eof $f1] || [eof $f2]} { + close $f1; close $f2 + return $diff + } + } + return 0 +} + # The database is initially empty. # set an hex key create some basic data # create table and insert operations should work @@ -408,8 +422,74 @@ db close file delete -force test.db # attach an encrypted database +# without specifying key, verify it fails +# even if the source passwords are the same +# because the kdf salts are different +setup test.db "'testkey'" +do_test attach-database-with-default-key { + sqlite_orig db2 test2.db + execsql { + PRAGMA key = 'testkey'; + PRAGMA cipher_add_random = "x'deadbaad'"; + CREATE TABLE t2(a,b); + INSERT INTO t2 VALUES ('test1', 'test2'); + } db2 + + catchsql { + ATTACH 'test.db' AS db; + } db2 + +} {1 {file is encrypted or is not a database}} +db2 close +file delete -force test.db +file delete -force test2.db + +# attach an encrypted database +# without specifying key, verify it attaches +# correctly when PRAGMA cipher_store_pass = 1 +# is set. +do_test attach-database-with-default-key-using-cipher-store-pass { + + sqlite_orig db1 test.db + execsql { + PRAGMA key = 'testkey'; + CREATE TABLE t1(a,b); + INSERT INTO t1(a,b) VALUES('foo', 'bar'); + } db1 + db1 close + + sqlite_orig db2 test2.db + execsql { + PRAGMA key = 'testkey'; + CREATE TABLE t2(a,b); + INSERT INTO t2 VALUES ('test1', 'test2'); + } db2 + db2 close + + sqlite_orig db1 test.db + execsql { + PRAGMA key = 'testkey'; + PRAGMA cipher_store_pass = 1; + ATTACH DATABASE 'test2.db' as db2; + SELECT sqlcipher_export('db2'); + DETACH DATABASE db2; + } db1 + db1 close + + sqlite_orig db2 test2.db + execsql { + PRAGMA key = 'testkey'; + SELECT * FROM t1; + } db2 + +} {foo bar} +db2 close +file delete -force test.db +file delete -force test2.db + +# attach an encrypted database # where both database have the same -# key +# key explicitly setup test.db "'testkey'" do_test attach-database-with-same-key { sqlite_orig db2 test2.db @@ -422,7 +502,7 @@ do_test attach-database-with-same-key { execsql { SELECT count(*) FROM t2; - ATTACH 'test.db' AS db; + ATTACH 'test.db' AS db KEY 'testkey'; SELECT count(*) FROM db.t1; } db2 @@ -607,7 +687,7 @@ file delete -force test.db # create an unencrypted database, attach a new encrypted volume # copy data between, verify the encypted database is good afterwards -do_test unencryped-attach { +do_test unencrypted-attach { sqlite_orig db test.db execsql { @@ -641,7 +721,7 @@ file delete -force test2.db # create an unencrypted database, attach a new encrypted volume # using a raw key copy data between, verify the encypted # database is good afterwards -do_test unencryped-attach-raw-key { +do_test unencrypted-attach-raw-key { sqlite_orig db test.db execsql { @@ -672,9 +752,45 @@ db2 close file delete -force test.db file delete -force test2.db +# create an encrypted database, attach an default-key encrypted volume +# copy data between, verify the second database +do_test encrypted-attach-default-key { + sqlite_orig db test.db + + execsql { + PRAGMA key='testkey'; + CREATE TABLE t1(a,b); + BEGIN; + } + + for {set i 1} {$i<=1000} {incr i} { + set r [expr {int(rand()*500000)}] + execsql "INSERT INTO t1 VALUES($i,$r);" + } + + execsql { + COMMIT; + ATTACH DATABASE 'test2.db' AS test; + CREATE TABLE test.t1(a,b); + INSERT INTO test.t1 SELECT * FROM t1; + DETACH DATABASE test; + } + + sqlite_orig db2 test2.db + + execsql { + PRAGMA key='testkey'; + SELECT count(*) FROM t1; + } db2 +} {1000} +db close +db2 close +file delete -force test.db +file delete -force test2.db + # create an encrypted database, attach an unencrypted volume # copy data between, verify the unencypted database is good afterwards -do_test encryped-attach-unencrypted { +do_test encrypted-attach-unencrypted { sqlite_orig db test.db execsql { @@ -683,7 +799,7 @@ do_test encryped-attach-unencrypted { sqlite_orig db2 test2.db execsql { - PRAGMA key='testkey'; + PRAGMA key = 'testkey'; CREATE TABLE t1(a,b); BEGIN; } db2 @@ -711,7 +827,7 @@ file delete -force test2.db # create an unencrypted database, attach an unencrypted volume # copy data between, verify the unencypted database is good afterwards -do_test unencryped-attach-unencrypted { +do_test unencrypted-attach-unencrypted { sqlite_orig db test.db execsql { @@ -875,16 +991,18 @@ file delete -force test.db # open a 1.1.8 database using the new code, HMAC disabled do_test open-1.1.8-database { - sqlite_orig db sqlcipher-1.1.8-testkey.db + file copy -force sqlcipher-1.1.8-testkey.db test.db + sqlite_orig db test.db execsql { PRAGMA key = 'testkey'; - PRAGMA cipher_use_hmac = OFF; + PRAGMA cipher_use_hmac = off; + PRAGMA kdf_iter = 4000; SELECT count(*) FROM t1; - SELECT * FROM t1; + SELECT distinct * FROM t1; } -} {4 1 1 one one 1 2 one two} +} {75709 1 1 one one 1 2 one two 1 2} db close - +file delete -force test.db # open a 1.1.8 database without hmac, then copy the data do_test attach-and-copy-1.1.8 { @@ -893,6 +1011,7 @@ do_test attach-and-copy-1.1.8 { execsql { PRAGMA key = 'testkey'; PRAGMA cipher_use_hmac = OFF; + PRAGMA kdf_iter = 4000; ATTACH DATABASE 'test.db' AS db2 KEY 'testkey-hmac'; CREATE TABLE db2.t1(a,b); INSERT INTO db2.t1 SELECT * FROM main.t1; @@ -904,9 +1023,9 @@ do_test attach-and-copy-1.1.8 { execsql { PRAGMA key = 'testkey-hmac'; SELECT count(*) FROM t1; - SELECT * FROM t1; + SELECT distinct * FROM t1; } -} {4 1 1 one one 1 2 one two} +} {75709 1 1 one one 1 2 one two 1 2} db close file delete -force test.db @@ -1350,22 +1469,24 @@ do_test cipher-options-before-keys { db close file delete -force test.db -# open a 1.1.8 database (no HMAC), then +# open a 1.1.8 database (no HMAC, 4K iter), then # try to open another 1.1.8 database. The # attached database should have the same hmac # setting as the original -do_test default-use-hmac-attach { +do_test default-hmac-kdf-attach { file copy -force sqlcipher-1.1.8-testkey.db test.db sqlite_orig db test.db execsql { PRAGMA cipher_default_use_hmac = OFF; + PRAGMA cipher_default_kdf_iter = 4000; PRAGMA key = 'testkey'; SELECT count(*) FROM t1; - ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2; + ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey'; SELECT count(*) from db2.t1; PRAGMA cipher_default_use_hmac = ON; + PRAGMA cipher_default_kdf_iter = 64000; } -} {4 4} +} {75709 75709} db close file delete -force test.db @@ -1378,18 +1499,18 @@ do_test attach-1.1.8-database-from-2.0-fails { catchsql { PRAGMA key = 'testkey'; CREATE table t1(a,b); - ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2; + ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey'; } } {1 {file is encrypted or is not a database}} db close file delete -force test.db -# open a 2.0 database (with HMAC), then +# open a 2.0 database (with HMAC, 4k iter), then # set the default hmac setting to OFF. # try to a 1.1.8 database. this should # succeed now that hmac is off by default # before the attach -do_test change-default-use-hmac-attach { +do_test change-default-hmac-kdf-attach { sqlite_orig db test.db execsql { PRAGMA key = 'testkey'; @@ -1402,11 +1523,13 @@ do_test change-default-use-hmac-attach { PRAGMA key = 'testkey'; SELECT count(*) FROM t1; PRAGMA cipher_default_use_hmac = OFF; - ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2; + PRAGMA cipher_default_kdf_iter = 4000; + ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey'; SELECT count(*) from db2.t1; PRAGMA cipher_default_use_hmac = ON; + PRAGMA cipher_default_kdf_iter = 64000; } -} {1 4} +} {1 75709} db close file delete -force test.db @@ -1418,7 +1541,7 @@ do_test verify-pragma-cipher-version { execsql { PRAGMA cipher_version; } -} {2.2.1} +} {3.2.0} db close file delete -force test.db @@ -1580,16 +1703,29 @@ do_test multipage-schema-autovacuum-shortread-wal { db close file delete -force test.db +# open a 3.0 database with little endian hmac page numbers (default) +# verify it can be opened +do_test open-3.0-le-database { + sqlite_orig db sqlcipher-3.0-testkey.db + execsql { + PRAGMA key = 'testkey'; + SELECT count(*) FROM t1; + SELECT distinct * FROM t1; + } +} {78536 1 1 one one 1 2 one two} +db close + # open a 2.0 database with little endian hmac page numbers (default) # verify it can be opened do_test open-2.0-le-database { sqlite_orig db sqlcipher-2.0-le-testkey.db execsql { PRAGMA key = 'testkey'; + PRAGMA kdf_iter = 4000; SELECT count(*) FROM t1; - SELECT * FROM t1; + SELECT distinct * FROM t1; } -} {4 1 1 one one 1 2 one two} +} {78536 1 1 one one 1 2 one two} db close # open a 2.0 database with big-endian hmac page numbers @@ -1599,10 +1735,11 @@ do_test open-2.0-be-database { execsql { PRAGMA key = 'testkey'; PRAGMA cipher_hmac_pgno = be; + PRAGMA kdf_iter = 4000; SELECT count(*) FROM t1; - SELECT * FROM t1; + SELECT distinct * FROM t1; } -} {4 1 1 one one 1 2 one two} +} {78536 1 1 one one 1 2 one two} db close # open a 2.0 database with big-endian hmac page numbers @@ -1615,6 +1752,7 @@ do_test be-to-le-migration { execsql { PRAGMA key = 'testkey'; PRAGMA cipher_hmac_pgno = be; + PRAGMA kdf_iter = 4000; ATTACH DATABASE 'test.db' AS db2 KEY 'testkey'; CREATE TABLE db2.t1(a,b); INSERT INTO db2.t1 SELECT * FROM main.t1; @@ -1626,9 +1764,9 @@ do_test be-to-le-migration { execsql { PRAGMA key = 'testkey'; SELECT count(*) FROM t1; - SELECT * FROM t1; + SELECT distinct * FROM t1; } -} {4 1 1 one one 1 2 one two} +} {78536 1 1 one one 1 2 one two} db close file delete -force test.db @@ -1684,6 +1822,31 @@ do_test verify-pragma-cipher-default-use-hmac-off { db close file delete -force test.db +# verify the pragma default_cipher_kdf_iter +# is set to 64000 by default +do_test verify-pragma-cipher-default-kdf-iter-default { + sqlite_orig db test.db + execsql { + PRAGMA cipher_default_kdf_iter; + } +} {64000} +db close +file delete -force test.db + + +# verify the pragma default_cipher_kdf_ter +# reports changes +do_test verify-pragma-cipher-default-use-hmac-off { + sqlite_orig db test.db + execsql { + PRAGMA cipher_default_kdf_iter = 1000; + PRAGMA cipher_default_kdf_iter; + PRAGMA cipher_default_kdf_iter = 64000; + } +} {1000} +db close +file delete -force test.db + # verify the pragma kdf_iter # reports the default value do_test verify-pragma-kdf-iter-reports-default { @@ -1692,7 +1855,7 @@ do_test verify-pragma-kdf-iter-reports-default { PRAGMA key = 'test'; PRAGMA kdf_iter; } -} {4000} +} {64000} db close file delete -force test.db @@ -1843,12 +2006,13 @@ do_test open-2.0-beta-database { sqlite_orig db sqlcipher-2.0-beta-testkey.db execsql { PRAGMA key = 'testkey'; + PRAGMA kdf_iter = 4000; PRAGMA fast_kdf_iter = 4000; PRAGMA cipher_hmac_salt_mask = "x'00'"; SELECT count(*) FROM t1; - SELECT * FROM t1; + SELECT distinct * FROM t1; } -} {2 test-0-0 test-0-1 test-1-0 test-1-1} +} {38768 test-0-0 test-0-1 test-1-0 test-1-1} db close # open a 2.0 beta database @@ -1861,6 +2025,7 @@ do_test 2.0-beta-to-2.0-migration { execsql { PRAGMA key = 'testkey'; PRAGMA cipher_hmac_salt_mask = "x'00'"; + PRAGMA kdf_iter = 4000; PRAGMA fast_kdf_iter = 4000; SELECT count(*) FROM sqlite_master; @@ -1876,7 +2041,7 @@ do_test 2.0-beta-to-2.0-migration { sqlite_orig db test.db execsql { PRAGMA key = 'testkey'; - SELECT * FROM t1; + SELECT distinct * FROM t1; } } {test-0-0 test-0-1 test-1-0 test-1-1} db close @@ -1902,4 +2067,194 @@ if_built_with_commoncrypto verify-default-cipher { db close file delete -force test.db +do_test migrate-1.1.8-database-to-3x-format { + file copy -force sqlcipher-1.1.8-testkey.db test.db + sqlite_orig db test.db + execsql { + PRAGMA key = 'testkey'; + PRAGMA cipher_migrate; + } + db close + + sqlite_orig db test.db + execsql { + PRAGMA key = 'testkey'; + SELECT count(*) FROM sqlite_master; + } +} {1} +db close +file delete -force test.db + +do_test migrate-2-0-le-database-to-3x-format { + file copy -force sqlcipher-2.0-le-testkey.db test.db + sqlite_orig db test.db + execsql { + PRAGMA key = 'testkey'; + PRAGMA cipher_migrate; + } + db close + + sqlite_orig db test.db + execsql { + PRAGMA key = 'testkey'; + SELECT count(*) FROM sqlite_master; + } +} {1} +db close +file delete -force test.db + +do_test key-database-by-name { + sqlite_orig db test.db + execsql { + attach database 'new.db' as new; + pragma new.key = 'foo'; + create table new.t1(a,b); + insert into new.t1(a,b) values('foo', 'bar'); + detach database new; + } + db close + + sqlite_orig db new.db + execsql { + pragma key = 'foo'; + select * from t1; + } +} {foo bar} +db close +file delete -force test.db +file delete -force new.db + +do_test key-multiple-databases-with-different-keys-using-pragma { + sqlite_orig db test.db + execsql { + pragma key = 'foobar'; + create table t1(a,b); + insert into t1(a,b) values('baz','qux'); + attach database 'new.db' as new; + pragma new.key = 'foo'; + create table new.t1(a,b); + insert into new.t1(a,b) values('foo', 'bar'); + detach database new; + } + db close + + sqlite_orig db new.db + execsql { + pragma key = 'foo'; + attach database 'test.db' as test key 'foobar'; + select * from t1; + select * from test.t1; + } +} {foo bar baz qux} +db close +file delete -force test.db +file delete -force new.db + +do_test rekey-database-by-name { + sqlite_orig db test.db + execsql { + attach database 'new.db' as new; + pragma new.key = 'foo'; + create table new.t1(a,b); + insert into new.t1(a,b) values('foo', 'bar'); + pragma new.rekey = 'bar'; + detach database new; + } + db close + + sqlite_orig db new.db + execsql { + pragma key = 'bar'; + select * from t1; + } +} {foo bar} +db close +file delete -force test.db +file delete -force new.db + +# Requires SQLCipher to be built with -DSQLCIPHER_TEST +if_built_with_libtomcrypt verify-random-data-alters-file-content { + file delete -force test.db + file delete -force test2.db + file delete -force test3.db + set rc {} + + sqlite_orig db test.db + execsql { + PRAGMA key="x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + create table t1(a,b); + } + db close + sqlite_orig db test2.db + execsql { + PRAGMA key="x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + create table t1(a,b); + } + db close + sqlite_orig db test3.db + execsql { + PRAGMA key="x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA cipher_add_random = "x'deadbaad'"; + create table t1(a,b); + } + db close + lappend rc [cmpFilesChunked test.db test2.db] + lappend rc [cmpFilesChunked test2.db test3.db] +} {0 1} +file delete -force test.db +file delete -force test2.db +file delete -force test3.db + +do_test can-migrate-with-keys-longer-than-64-characters { + sqlite_orig db test.db + execsql { + PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345"; + PRAGMA kdf_iter = 4000; + PRAGMA user_version = 5; + } + db close + + sqlite_orig db test.db + execsql { + PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345"; + PRAGMA cipher_migrate; + } + db close + + sqlite_orig db test.db + execsql { + PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345"; + PRAGMA user_version; + } +} {5} +db close +file delete -force test.db + +do_test can-migrate-with-raw-hex-key { + sqlite_orig db test.db + execsql { + PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA kdf_iter = 4000; + PRAGMA cipher_use_hmac = off; + PRAGMA user_version = 5; + } + db close + + sqlite_orig db test.db + execsql { + PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA cipher_migrate; + } + + sqlite_orig db test.db + execsql { + PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA user_version; + } + +} {5} +db close +file delete -force test.db + +sqlite3_test_control_pending_byte $old_pending_byte finish_test diff --git a/test/date.test b/test/date.test index a30402c..b1d1c67 100644 --- a/test/date.test +++ b/test/date.test @@ -528,4 +528,27 @@ if {0==[sqlite3 -has-codec]} { } {1} } } + +# Verify that multiple calls to date functions with 'now' return the +# same answer. +# +# EVIDENCE-OF: R-34818-13664 The 'now' argument to date and time +# functions always returns exactly the same value for multiple +# invocations within the same sqlite3_step() call. +# +proc sleeper {} {after 100} +do_test date-15.1 { + db func sleeper sleeper + db eval { + SELECT c - a FROM (SELECT julianday('now') AS a, + sleeper(), julianday('now') AS c); + } +} {0.0} +do_test date-15.2 { + db eval { + SELECT a==b FROM (SELECT current_timestamp AS a, + sleeper(), current_timestamp AS b); + } +} {1} + finish_test diff --git a/test/dbstatus.test b/test/dbstatus.test index 9793df3..368c6b2 100644 --- a/test/dbstatus.test +++ b/test/dbstatus.test @@ -61,7 +61,7 @@ proc lookaside {db} { } } -ifcapable stat3 { +ifcapable stat4||stat3 { set STAT3 1 } else { set STAT3 0 @@ -134,7 +134,7 @@ foreach ::lookaside_buffer_size {0 64 120} { CREATE TABLE t2(c, d); CREATE VIEW v1 AS SELECT * FROM t1 UNION SELECT * FROM t2; } - 6y { + 6k { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t1(a,b); @@ -204,6 +204,11 @@ foreach ::lookaside_buffer_size {0 64 120} { set nSchema4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1] set nFree [expr {$nAlloc1-$nAlloc2}] + # Tests for which the test name ends in an "k" report slightly less + # memory than is actually freed when all schema items are finalized. + # This is because memory allocated by KeyInfo objects is no longer + # counted as "schema memory". + # # Tests for which the test name ends in an "x" report slightly less # memory than is actually freed when all schema items are finalized. # This is because memory allocated by virtual table implementations @@ -214,13 +219,14 @@ foreach ::lookaside_buffer_size {0 64 120} { # much greater than just that reported by DBSTATUS_SCHEMA_USED in this # case. # - # Some of the memory used for sqlite_stat3 is unaccounted for by + # Some of the memory used for sqlite_stat4 is unaccounted for by # dbstatus. # # Finally, on osx the estimate of memory used by the schema may be # slightly low. # - if {[string match *x $tn] || $AUTOVACUUM + if {[string match *k $tn] + || [string match *x $tn] || $AUTOVACUUM || ([string match *y $tn] && $STAT3) || ($::tcl_platform(os) == "Darwin") } { @@ -246,7 +252,7 @@ foreach ::lookaside_buffer_size {0 64 120} { # lookaside memory allocated by SQLite, and the memory allocated # for the prepared statements according to sqlite3_db_status(). # - # 3. Finalize all prepared statements Measure the total memory + # 3. Finalize all prepared statements. Measure the total memory # and the prepared statement memory again. # # 4. Repeat step 2. diff --git a/test/default.test b/test/default.test index 95a4ee0..d6b6f97 100644 --- a/test/default.test +++ b/test/default.test @@ -64,4 +64,39 @@ ifcapable pragma { } {0 c {} 0 'abc' 0} } +do_execsql_test default-3.1 { + CREATE TABLE t3( + a INTEGER PRIMARY KEY AUTOINCREMENT, + b INT DEFAULT 12345 UNIQUE NOT NULL CHECK( b>=0 AND b<99999 ), + c VARCHAR(123,456) DEFAULT 'hello' NOT NULL ON CONFLICT REPLACE, + d REAL, + e FLOATING POINT(5,10) DEFAULT 4.36, + f NATIONAL CHARACTER(15) COLLATE RTRIM, + g LONG INTEGER DEFAULT( 3600*12 ) + ); + INSERT INTO t3 VALUES(null, 5, 'row1', '5.25', 'xyz', 321, '432'); + SELECT a, typeof(a), b, typeof(b), c, typeof(c), + d, typeof(d), e, typeof(e), f, typeof(f), + g, typeof(g) FROM t3; +} {1 integer 5 integer row1 text 5.25 real xyz text 321 text 432 integer} +do_execsql_test default-3.2 { + DELETE FROM t3; + INSERT INTO t3 DEFAULT VALUES; + SELECT * FROM t3; +} {2 12345 hello {} 4.36 {} 43200} +do_execsql_test default-3.3 { + CREATE TABLE t300( + a INT DEFAULT 2147483647, + b INT DEFAULT 2147483648, + c INT DEFAULT +9223372036854775807, + d INT DEFAULT -2147483647, + e INT DEFAULT -2147483648, + f INT DEFAULT -9223372036854775808, + g INT DEFAULT (-(-9223372036854775808)), + h INT DEFAULT (-(-9223372036854775807)) + ); + INSERT INTO t300 DEFAULT VALUES; + SELECT * FROM t300; +} {2147483647 2147483648 9223372036854775807 -2147483647 -2147483648 -9223372036854775808 9.22337203685478e+18 9223372036854775807} + finish_test diff --git a/test/descidx1.test b/test/descidx1.test index c7fab34..a223664 100644 --- a/test/descidx1.test +++ b/test/descidx1.test @@ -197,12 +197,12 @@ ifcapable bloblit { } {1.0 2.2 2.0 2.1 2.3 3.0 4.0 5.0 6.0} do_test descidx1-4.3 { execsql { - SELECT d FROM t2 WHERE a>=2; + SELECT d FROM t2 WHERE a>=2 ORDER BY a; } } {2.2 2.0 2.1 2.3 3.0 4.0 5.0 6.0} do_test descidx1-4.4 { execsql { - SELECT d FROM t2 WHERE a>2; + SELECT d FROM t2 WHERE a>2 ORDER BY a; } } {3.0 4.0 5.0 6.0} do_test descidx1-4.5 { diff --git a/test/distinct.test b/test/distinct.test index fcbe4e6..78c2c1d 100644 --- a/test/distinct.test +++ b/test/distinct.test @@ -162,10 +162,10 @@ do_execsql_test 2.0 { foreach {tn sql temptables res} { 1 "a, b FROM t1" {} {A B a b} 2 "b, a FROM t1" {} {B A b a} - 3 "a, b, c FROM t1" {hash} {a b c A B C} + 3 "a, b, c FROM t1" {hash} {A B C a b c} 4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c} 5 "b FROM t1 WHERE a = 'a'" {} {b} - 6 "b FROM t1" {hash} {b B} + 6 "b FROM t1 ORDER BY +b COLLATE binary" {btree hash} {B b} 7 "a FROM t1" {} {A a} 8 "b COLLATE nocase FROM t1" {} {b} 9 "b COLLATE nocase FROM t1 ORDER BY b COLLATE nocase" {} {b} @@ -197,4 +197,29 @@ do_test 3.1 { }] } {0} +#------------------------------------------------------------------------- +# Ticket [fccbde530a6583bf2748400919f1603d5425995c] (2014-01-08) +# The logic that computes DISTINCT sometimes thinks that a zeroblob() +# and a blob of all zeros are different when they should be the same. +# +do_execsql_test 4.1 { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1(a INTEGER); + INSERT INTO t1 VALUES(3); + INSERT INTO t1 VALUES(2); + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(2); + INSERT INTO t1 VALUES(3); + INSERT INTO t1 VALUES(1); + CREATE TABLE t2(x); + INSERT INTO t2 + SELECT DISTINCT + CASE a WHEN 1 THEN x'0000000000' + WHEN 2 THEN zeroblob(5) + ELSE 'xyzzy' END + FROM t1; + SELECT quote(x) FROM t2 ORDER BY 1; +} {'xyzzy' X'0000000000'} + finish_test diff --git a/test/e_createtable.test b/test/e_createtable.test index 351a0f7..08f606f 100644 --- a/test/e_createtable.test +++ b/test/e_createtable.test @@ -58,8 +58,6 @@ proc table_list {} { } -# EVIDENCE-OF: R-47266-09114 -- syntax diagram type-name -# do_createtable_tests 0.1.1 -repair { drop_all_tables } { @@ -79,7 +77,7 @@ do_createtable_tests 0.1.2 -error { } -# EVIDENCE-OF: R-60689-48779 -- syntax diagram column-constraint +# syntax diagram column-constraint # do_createtable_tests 0.2.1 -repair { drop_all_tables @@ -126,7 +124,7 @@ do_createtable_tests 0.2.1 -repair { } {} } -# EVIDENCE-OF: R-58169-51804 -- syntax diagram table-constraint +# -- syntax diagram table-constraint # do_createtable_tests 0.3.1 -repair { drop_all_tables @@ -145,7 +143,7 @@ do_createtable_tests 0.3.1 -repair { 4.1 "CREATE TABLE t1(c1, c2, FOREIGN KEY(c1) REFERENCES t2)" {} } -# EVIDENCE-OF: R-44826-22243 -- syntax diagram column-def +# -- syntax diagram column-def # do_createtable_tests 0.4.1 -repair { drop_all_tables @@ -160,7 +158,7 @@ do_createtable_tests 0.4.1 -repair { } {} } -# EVIDENCE-OF: R-45698-45677 -- syntax diagram create-table-stmt +# -- syntax diagram create-table-stmt # do_createtable_tests 0.5.1 -repair { drop_all_tables @@ -185,7 +183,6 @@ do_createtable_tests 0.5.1 -repair { 15 "CREATE TABLE t1 AS SELECT count(*), max(b), min(a) FROM t2" {} } -# EVIDENCE-OF: R-24369-11919 -- syntax diagram foreign-key-clause # # 1: Explicit parent-key columns. # 2: Implicit child-key columns. @@ -887,9 +884,10 @@ do_execsql_test e_createtable-3.3.1 { ); } {} -# EVIDENCE-OF: R-10288-43169 For the purposes of the DEFAULT clause, an +# EVIDENCE-OF: R-36381-62919 For the purposes of the DEFAULT clause, an # expression is considered constant provided that it does not contain -# any sub-queries or string constants enclosed in double quotes. +# any sub-queries, column or table references, or string literals +# enclosed in double-quotes instead of single-quotes. # do_createtable_tests 3.4.1 -error { default value of column [x] is not constant @@ -1106,8 +1104,8 @@ do_catchsql_test e_createtable-3.11.5 { # EVIDENCE-OF: R-52382-54248 Each table in SQLite may have at most one # PRIMARY KEY. # -# EVIDENCE-OF: R-18080-47271 If there is more than one PRIMARY KEY -# clause in a single CREATE TABLE statement, it is an error. +# EVIDENCE-OF: R-31826-01813 An error is raised if more than one PRIMARY +# KEY clause appears in a CREATE TABLE statement. # # To test the two above, show that zero primary keys is Ok, one primary # key is Ok, and two or more primary keys is an error. @@ -1130,6 +1128,17 @@ do_createtable_tests 4.1.2 -error { 6 "CREATE TABLE t5(a INTEGER PRIMARY KEY, b, c, PRIMARY KEY(a))" {} } +# EVIDENCE-OF: R-54755-39291 The PRIMARY KEY is optional for ordinary +# tables but is required for WITHOUT ROWID tables. +# +do_catchsql_test 4.1.3 { + CREATE TABLE t6(a, b); --ok +} {0 {}} +do_catchsql_test 4.1.4 { + CREATE TABLE t7(a, b) WITHOUT ROWID; --Error, no PRIMARY KEY +} {1 {PRIMARY KEY missing on table t7}} + + proc table_pk {tbl} { set pk [list] db eval "pragma table_info($tbl)" a { @@ -1163,12 +1172,12 @@ do_createtable_tests 4.2 -repair { 2.3 "CREATE TABLE t5(a, b INTEGER PRIMARY KEY, c)" {b} } -# EVIDENCE-OF: R-33986-09410 Each row in a table with a primary key must -# feature a unique combination of values in its primary key columns. +# EVIDENCE-OF: R-59124-61339 Each row in a table with a primary key must +# have a unique combination of values in its primary key columns. # -# EVIDENCE-OF: R-39102-06737 If an INSERT or UPDATE statement attempts -# to modify the table content so that two or more rows feature identical -# primary key values, it is a constraint violation. +# EVIDENCE-OF: R-06471-16287 If an INSERT or UPDATE statement attempts +# to modify the table content so that two or more rows have identical +# primary key values, that is a constraint violation. # drop_all_tables do_execsql_test 4.3.0 { @@ -1185,13 +1194,14 @@ do_execsql_test 4.3.0 { INSERT INTO t2 VALUES(X'ABCDEF', 'three'); } {} -do_createtable_tests 4.3.1 -error { %s not unique } { +do_createtable_tests 4.3.1 -error {UNIQUE constraint failed: t1.x} { 1 "INSERT INTO t1 VALUES(0, 0)" {"column x is"} 2 "INSERT INTO t1 VALUES(45.5, 'abc')" {"column x is"} 3 "INSERT INTO t1 VALUES(0.0, 'abc')" {"column x is"} 4 "INSERT INTO t1 VALUES('brambles', 'abc')" {"column x is"} 5 "INSERT INTO t1 VALUES(X'ABCDEF', 'abc')" {"column x is"} - +} +do_createtable_tests 4.3.1 -error {UNIQUE constraint failed: t2.x, t2.y} { 6 "INSERT INTO t2 VALUES(0, 'zero')" {"columns x, y are"} 7 "INSERT INTO t2 VALUES(45.5, 'one')" {"columns x, y are"} 8 "INSERT INTO t2 VALUES(0.0, 'zero')" {"columns x, y are"} @@ -1211,13 +1221,14 @@ do_createtable_tests 4.3.2 { 9 "INSERT INTO t2 VALUES('brambles', 'abc')" {} 10 "INSERT INTO t2 VALUES(X'ABCDEF', 'abc')" {} } -do_createtable_tests 4.3.3 -error { %s not unique } { +do_createtable_tests 4.3.3 -error {UNIQUE constraint failed: t1.x} { 1 "UPDATE t1 SET x=0 WHERE y='two'" {"column x is"} 2 "UPDATE t1 SET x='brambles' WHERE y='three'" {"column x is"} 3 "UPDATE t1 SET x=45.5 WHERE y='zero'" {"column x is"} 4 "UPDATE t1 SET x=X'ABCDEF' WHERE y='one'" {"column x is"} 5 "UPDATE t1 SET x=0.0 WHERE y='three'" {"column x is"} - +} +do_createtable_tests 4.3.3 -error {UNIQUE constraint failed: t2.x, t2.y} { 6 "UPDATE t2 SET x=0, y='zero' WHERE y='two'" {"columns x, y are"} 7 "UPDATE t2 SET x='brambles', y='two' WHERE y='three'" {"columns x, y are"} @@ -1253,8 +1264,9 @@ do_createtable_tests 4.4 { 14 "INSERT INTO t2 VALUES(NULL, NULL)" {} } -# EVIDENCE-OF: R-61866-38053 Unless the column is an INTEGER PRIMARY KEY -# SQLite allows NULL values in a PRIMARY KEY column. +# EVIDENCE-OF: R-35113-43214 Unless the column is an INTEGER PRIMARY KEY +# or the table is a WITHOUT ROWID table or the column is declared NOT +# NULL, SQLite allows NULL values in a PRIMARY KEY column. # # If the column is an integer primary key, attempting to insert a NULL # into the column triggers the auto-increment behavior. Attempting @@ -1276,6 +1288,14 @@ do_catchsql_test 4.5.3 { INSERT INTO t3 VALUES(2, 5, 3); UPDATE t3 SET u = NULL WHERE s = 2; } {1 {datatype mismatch}} +do_catchsql_test 4.5.4 { + CREATE TABLE t4(s, u INT PRIMARY KEY, v) WITHOUT ROWID; + INSERT INTO t4 VALUES(1, NULL, 2); +} {1 {NOT NULL constraint failed: t4.u}} +do_catchsql_test 4.5.5 { + CREATE TABLE t5(s, u INT PRIMARY KEY NOT NULL, v); + INSERT INTO t5 VALUES(1, NULL, 2); +} {1 {NOT NULL constraint failed: t5.u}} # EVIDENCE-OF: R-00227-21080 A UNIQUE constraint is similar to a PRIMARY # KEY constraint, except that a single table may have any number of @@ -1289,14 +1309,12 @@ do_createtable_tests 4.6 { 4 "CREATE TABLE t4(a, b, c, UNIQUE(a, b, c))" {} } -# EVIDENCE-OF: R-55240-58877 For each UNIQUE constraint on the table, -# each row must feature a unique combination of values in the columns +# EVIDENCE-OF: R-30981-64168 For each UNIQUE constraint on the table, +# each row must contain a unique combination of values in the columns # identified by the UNIQUE constraint. # -# EVIDENCE-OF: R-47733-51480 If an INSERT or UPDATE statement attempts -# to modify the table content so that two or more rows feature identical -# values in a set of columns that are subject to a UNIQUE constraint, it -# is a constraint violation. +# EVIDENCE-OF: R-59124-61339 Each row in a table with a primary key must +# have a unique combination of values in its primary key columns. # do_execsql_test 4.7.0 { INSERT INTO t1 VALUES(1, 2); @@ -1308,29 +1326,29 @@ do_execsql_test 4.7.0 { INSERT INTO t4 VALUES('xyx', 2, 1); INSERT INTO t4 VALUES('uvw', 1, 1); } -do_createtable_tests 4.7.1 -error { %s not unique } { - 1 "INSERT INTO t1 VALUES(1, 'one')" {{column a is}} - 2 "INSERT INTO t1 VALUES(4.3, 'two')" {{column a is}} - 3 "INSERT INTO t1 VALUES('reveal', 'three')" {{column a is}} - 4 "INSERT INTO t1 VALUES(X'123456', 'four')" {{column a is}} +do_createtable_tests 4.7.1 -error {UNIQUE constraint failed: %s} { + 1 "INSERT INTO t1 VALUES(1, 'one')" {{t1.a}} + 2 "INSERT INTO t1 VALUES(4.3, 'two')" {{t1.a}} + 3 "INSERT INTO t1 VALUES('reveal', 'three')" {{t1.a}} + 4 "INSERT INTO t1 VALUES(X'123456', 'four')" {{t1.a}} - 5 "UPDATE t1 SET a = 1 WHERE rowid=2" {{column a is}} - 6 "UPDATE t1 SET a = 4.3 WHERE rowid=3" {{column a is}} - 7 "UPDATE t1 SET a = 'reveal' WHERE rowid=4" {{column a is}} - 8 "UPDATE t1 SET a = X'123456' WHERE rowid=1" {{column a is}} + 5 "UPDATE t1 SET a = 1 WHERE rowid=2" {{t1.a}} + 6 "UPDATE t1 SET a = 4.3 WHERE rowid=3" {{t1.a}} + 7 "UPDATE t1 SET a = 'reveal' WHERE rowid=4" {{t1.a}} + 8 "UPDATE t1 SET a = X'123456' WHERE rowid=1" {{t1.a}} - 9 "INSERT INTO t4 VALUES('xyx', 1, 1)" {{columns a, b, c are}} - 10 "INSERT INTO t4 VALUES('xyx', 2, 1)" {{columns a, b, c are}} - 11 "INSERT INTO t4 VALUES('uvw', 1, 1)" {{columns a, b, c are}} + 9 "INSERT INTO t4 VALUES('xyx', 1, 1)" {{t4.a, t4.b, t4.c}} + 10 "INSERT INTO t4 VALUES('xyx', 2, 1)" {{t4.a, t4.b, t4.c}} + 11 "INSERT INTO t4 VALUES('uvw', 1, 1)" {{t4.a, t4.b, t4.c}} - 12 "UPDATE t4 SET a='xyx' WHERE rowid=3" {{columns a, b, c are}} - 13 "UPDATE t4 SET b=1 WHERE rowid=2" {{columns a, b, c are}} - 14 "UPDATE t4 SET a=0, b=0, c=0" {{columns a, b, c are}} + 12 "UPDATE t4 SET a='xyx' WHERE rowid=3" {{t4.a, t4.b, t4.c}} + 13 "UPDATE t4 SET b=1 WHERE rowid=2" {{t4.a, t4.b, t4.c}} + 14 "UPDATE t4 SET a=0, b=0, c=0" {{t4.a, t4.b, t4.c}} } -# EVIDENCE-OF: R-21289-11559 As with PRIMARY KEY constraints, for the -# purposes of UNIQUE constraints NULL values are considered distinct -# from all other values (including other NULLs). +# EVIDENCE-OF: R-00404-17670 For the purposes of UNIQUE constraints, +# NULL values are considered distinct from all other values, including +# other NULLs. # do_createtable_tests 4.8 { 1 "INSERT INTO t1 VALUES(NULL, NULL)" {} @@ -1345,10 +1363,9 @@ do_createtable_tests 4.8 { 9 "UPDATE t4 SET c = NULL" {} } -# EVIDENCE-OF: R-26983-26377 INTEGER PRIMARY KEY columns aside, both -# UNIQUE and PRIMARY KEY constraints are implemented by creating an -# index in the database (in the same way as a "CREATE UNIQUE INDEX" -# statement would). +# EVIDENCE-OF: R-55820-29984 In most cases, UNIQUE and PRIMARY KEY +# constraints are implemented by creating a unique index in the +# database. do_createtable_tests 4.9 -repair drop_all_tables -query { SELECT count(*) FROM sqlite_master WHERE type='index' } { @@ -1359,7 +1376,7 @@ do_createtable_tests 4.9 -repair drop_all_tables -query { 5 "CREATE TABLE t1(a PRIMARY KEY, b, c, UNIQUE(c, b))" 2 } -# EVIDENCE-OF: R-02252-33116 Such an index is used like any other index +# Obsolete: R-02252-33116 Such an index is used like any other index # in the database to optimize queries. # do_execsql_test 4.10.0 { @@ -1368,13 +1385,13 @@ do_execsql_test 4.10.0 { } do_createtable_tests 4.10 { 1 "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 5" - {0 0 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?) (~1 rows)}} + {0 0 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?)}} 2 "EXPLAIN QUERY PLAN SELECT * FROM t2 ORDER BY b, c" - {0 0 0 {SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1 (~1000000 rows)}} + {0 0 0 {SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1}} 3 "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE b=10 AND c>10" - {0 0 0 {SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?) (~2 rows)}} + {0 0 0 {SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?)}} } # EVIDENCE-OF: R-45493-35653 A CHECK constraint may be attached to a @@ -1407,21 +1424,21 @@ do_execsql_test 4.11 { INSERT INTO t2 SELECT * FROM x2; } -do_createtable_tests 4.11 -error {constraint failed} { - 1a "INSERT INTO x1 VALUES('one', 0)" {} - 1b "INSERT INTO t1 VALUES('one', -4.0)" {} +do_createtable_tests 4.11 -error {CHECK constraint failed: %s} { + 1a "INSERT INTO x1 VALUES('one', 0)" {x1} + 1b "INSERT INTO t1 VALUES('one', -4.0)" {t1} - 2a "INSERT INTO x2 VALUES('abc', 1)" {} - 2b "INSERT INTO t2 VALUES('abc', 1)" {} + 2a "INSERT INTO x2 VALUES('abc', 1)" {x2} + 2b "INSERT INTO t2 VALUES('abc', 1)" {t2} - 3a "INSERT INTO x2 VALUES(0, 'abc')" {} - 3b "INSERT INTO t2 VALUES(0, 'abc')" {} + 3a "INSERT INTO x2 VALUES(0, 'abc')" {x2} + 3b "INSERT INTO t2 VALUES(0, 'abc')" {t2} - 4a "UPDATE t1 SET b=-1 WHERE rowid=1" {} - 4b "UPDATE x1 SET b=-1 WHERE rowid=1" {} + 4a "UPDATE t1 SET b=-1 WHERE rowid=1" {t1} + 4b "UPDATE x1 SET b=-1 WHERE rowid=1" {x1} - 4a "UPDATE x2 SET a='' WHERE rowid=1" {} - 4b "UPDATE t2 SET a='' WHERE rowid=1" {} + 4a "UPDATE x2 SET a='' WHERE rowid=1" {x2} + 4b "UPDATE t2 SET a='' WHERE rowid=1" {t2} } # EVIDENCE-OF: R-34109-39108 If the CHECK expression evaluates to NULL, @@ -1472,9 +1489,7 @@ do_execsql_test 4.14.0 { INSERT INTO t3 VALUES('x', 'y', 'z'); INSERT INTO t3 VALUES(1, 2, 3); } -do_createtable_tests 4.14 -error { - %s may not be NULL -} { +do_createtable_tests 4.14 -error {NOT NULL constraint failed: %s} { 1 "INSERT INTO t1 VALUES(NULL, 'a')" {t1.a} 2 "INSERT INTO t2 VALUES(NULL, 'b')" {t2.a} 3 "INSERT INTO t3 VALUES('c', 'd', NULL)" {t3.c} @@ -1540,12 +1555,12 @@ do_execsql_test 4.15.0 { } foreach {tn tbl res ac data} { - 1 t1_ab {1 {column a is not unique}} 0 {1 one 2 two 3 three} - 2 t1_ro {1 {column a is not unique}} 1 {1 one 2 two} - 3 t1_fa {1 {column a is not unique}} 0 {1 one 2 two 3 three 4 string} + 1 t1_ab {1 {UNIQUE constraint failed: t1_ab.a}} 0 {1 one 2 two 3 three} + 2 t1_ro {1 {UNIQUE constraint failed: t1_ro.a}} 1 {1 one 2 two} + 3 t1_fa {1 {UNIQUE constraint failed: t1_fa.a}} 0 {1 one 2 two 3 three 4 string} 4 t1_ig {0 {}} 0 {1 one 2 two 3 three 4 string 6 string} 5 t1_re {0 {}} 0 {1 one 2 two 4 string 3 string 6 string} - 6 t1_xx {1 {column a is not unique}} 0 {1 one 2 two 3 three} + 6 t1_xx {1 {UNIQUE constraint failed: t1_xx.a}} 0 {1 one 2 two 3 three} } { catchsql COMMIT do_execsql_test 4.15.$tn.1 "BEGIN; INSERT INTO $tbl VALUES(3, 'three')" @@ -1558,12 +1573,12 @@ foreach {tn tbl res ac data} { do_execsql_test 4.15.$tn.4 "SELECT * FROM $tbl" $data } foreach {tn tbl res ac data} { - 1 t2_ab {1 {t2_ab.b may not be NULL}} 0 {1 one 2 two 3 three} - 2 t2_ro {1 {t2_ro.b may not be NULL}} 1 {1 one 2 two} - 3 t2_fa {1 {t2_fa.b may not be NULL}} 0 {1 one 2 two 3 three 4 xx} + 1 t2_ab {1 {NOT NULL constraint failed: t2_ab.b}} 0 {1 one 2 two 3 three} + 2 t2_ro {1 {NOT NULL constraint failed: t2_ro.b}} 1 {1 one 2 two} + 3 t2_fa {1 {NOT NULL constraint failed: t2_fa.b}} 0 {1 one 2 two 3 three 4 xx} 4 t2_ig {0 {}} 0 {1 one 2 two 3 three 4 xx 6 xx} - 5 t2_re {1 {t2_re.b may not be NULL}} 0 {1 one 2 two 3 three} - 6 t2_xx {1 {t2_xx.b may not be NULL}} 0 {1 one 2 two 3 three} + 5 t2_re {1 {NOT NULL constraint failed: t2_re.b}} 0 {1 one 2 two 3 three} + 6 t2_xx {1 {NOT NULL constraint failed: t2_xx.b}} 0 {1 one 2 two 3 three} } { catchsql COMMIT do_execsql_test 4.16.$tn.1 "BEGIN; INSERT INTO $tbl VALUES(3, 'three')" @@ -1576,12 +1591,16 @@ foreach {tn tbl res ac data} { do_execsql_test 4.16.$tn.4 "SELECT * FROM $tbl" $data } foreach {tn tbl res ac data} { - 1 t3_ab {1 {columns a, b are not unique}} 0 {1 one 2 two 3 three} - 2 t3_ro {1 {columns a, b are not unique}} 1 {1 one 2 two} - 3 t3_fa {1 {columns a, b are not unique}} 0 {1 one 2 two 3 three 4 three} + 1 t3_ab {1 {UNIQUE constraint failed: t3_ab.a, t3_ab.b}} + 0 {1 one 2 two 3 three} + 2 t3_ro {1 {UNIQUE constraint failed: t3_ro.a, t3_ro.b}} + 1 {1 one 2 two} + 3 t3_fa {1 {UNIQUE constraint failed: t3_fa.a, t3_fa.b}} + 0 {1 one 2 two 3 three 4 three} 4 t3_ig {0 {}} 0 {1 one 2 two 3 three 4 three 6 three} 5 t3_re {0 {}} 0 {1 one 2 two 4 three 3 three 6 three} - 6 t3_xx {1 {columns a, b are not unique}} 0 {1 one 2 two 3 three} + 6 t3_xx {1 {UNIQUE constraint failed: t3_xx.a, t3_xx.b}} + 0 {1 one 2 two 3 three} } { catchsql COMMIT do_execsql_test 4.17.$tn.1 "BEGIN; INSERT INTO $tbl VALUES(3, 'three')" @@ -1612,7 +1631,7 @@ do_execsql_test 4.18.1 { do_execsql_test 4.18.2 { BEGIN; INSERT INTO t4 VALUES(5, 6) } do_catchsql_test 4.18.3 { INSERT INTO t4 SELECT a+4, b+4 FROM t4 -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t4}} do_test e_createtable-4.18.4 { sqlite3_get_autocommit db } 0 do_execsql_test 4.18.5 { SELECT * FROM t4 } {1 2 3 4 5 6} @@ -1625,7 +1644,7 @@ do_execsql_test 4.19.0 { do_catchsql_test 4.19.1 { INSERT INTO t5 VALUES(NULL, 'not null') } {0 {}} do_execsql_test 4.19.2 { SELECT * FROM t5 } {} do_catchsql_test 4.19.3 { INSERT INTO t5 VALUES('not null', NULL) } \ - {1 {t5.b may not be NULL}} + {1 {NOT NULL constraint failed: t5.b}} do_execsql_test 4.19.4 { SELECT * FROM t5 } {} #------------------------------------------------------------------------ @@ -1636,6 +1655,10 @@ do_execsql_test 4.19.4 { SELECT * FROM t5 } {} # of the special case-independent names "rowid", "oid", or "_rowid_" in # place of a column name. # +# EVIDENCE-OF: R-06726-07466 A column name can be any of the names +# defined in the CREATE TABLE statement or one of the following special +# identifiers: "ROWID", "OID", or "_ROWID_". +# drop_all_tables do_execsql_test 5.1.0 { CREATE TABLE t1(x, y); @@ -1660,6 +1683,10 @@ do_createtable_tests 5.1 { # explicitly declared column and cannot be used to retrieve the integer # rowid value. # +# EVIDENCE-OF: R-44615-33286 The special identifiers only refer to the +# row key if the CREATE TABLE statement does not define a real column +# with the same name. +# do_execsql_test 5.2.0 { CREATE TABLE t2(oid, b); CREATE TABLE t3(a, _rowid_); @@ -1694,10 +1721,10 @@ proc is_integer_primary_key {tbl col} { }]] 0 } -# EVIDENCE-OF: R-53738-31673 With one exception, if a table has a -# primary key that consists of a single column, and the declared type of -# that column is "INTEGER" in any mixture of upper and lower case, then -# the column becomes an alias for the rowid. +# EVIDENCE-OF: R-47901-33947 With one exception noted below, if a rowid +# table has a primary key that consists of a single column and the +# declared type of that column is "INTEGER" in any mixture of upper and +# lower case, then the column becomes an alias for the rowid. # # EVIDENCE-OF: R-45951-08347 if the declaration of a column with # declared type "INTEGER" includes an "PRIMARY KEY DESC" clause, it does @@ -1750,16 +1777,16 @@ do_execsql_test 5.4.3 { do_catchsql_test 5.4.4.1 { INSERT INTO t6 VALUES(2) -} {1 {column pk is not unique}} +} {1 {UNIQUE constraint failed: t6.pk}} do_catchsql_test 5.4.4.2 { INSERT INTO t7 VALUES(2) -} {1 {column pk is not unique}} +} {1 {UNIQUE constraint failed: t7.pk}} do_catchsql_test 5.4.4.3 { INSERT INTO t8 VALUES(2) -} {1 {column pk is not unique}} +} {1 {UNIQUE constraint failed: t8.pk}} do_catchsql_test 5.4.4.4 { INSERT INTO t9 VALUES(2) -} {1 {column pk is not unique}} +} {1 {UNIQUE constraint failed: t9.pk}} # EVIDENCE-OF: R-56094-57830 the following three table declarations all # cause the column "x" to be an alias for the rowid (an integer primary diff --git a/test/e_delete.test b/test/e_delete.test index 31bb324..b857cf1 100644 --- a/test/e_delete.test +++ b/test/e_delete.test @@ -29,9 +29,8 @@ do_execsql_test e_delete-0.0 { CREATE INDEX i1 ON t1(a); } {} -# EVIDENCE-OF: R-62077-19799 -- syntax diagram delete-stmt -# -# EVIDENCE-OF: R-60796-31013 -- syntax diagram qualified-table-name +# -- syntax diagram delete-stmt +# -- syntax diagram qualified-table-name # do_delete_tests e_delete-0.1 { 1 "DELETE FROM t1" {} @@ -292,7 +291,7 @@ do_delete_tests e_delete-2.5 -error { near "%s": syntax error } { # of the DELETE statement is extended by the addition of optional ORDER # BY and LIMIT clauses: # -# EVIDENCE-OF: R-52694-53361 -- syntax diagram delete-stmt-limited +# -- syntax diagram delete-stmt-limited # do_delete_tests e_delete-3.1 { 1 "DELETE FROM t1 LIMIT 5" {} diff --git a/test/e_droptrigger.test b/test/e_droptrigger.test index fe96104..84dfe72 100644 --- a/test/e_droptrigger.test +++ b/test/e_droptrigger.test @@ -69,7 +69,7 @@ proc droptrigger_reopen_db {{event INSERT}} { } -# EVIDENCE-OF: R-27975-10951 -- syntax diagram drop-trigger-stmt +# -- syntax diagram drop-trigger-stmt # do_droptrigger_tests 1.1 -repair { droptrigger_reopen_db diff --git a/test/e_dropview.test b/test/e_dropview.test index 4a4b9c3..143dce2 100644 --- a/test/e_dropview.test +++ b/test/e_dropview.test @@ -70,7 +70,7 @@ proc do_dropview_tests {nm args} { uplevel do_select_tests $nm $args } -# EVIDENCE-OF: R-53136-36436 -- syntax diagram drop-view-stmt +# -- syntax diagram drop-view-stmt # # All paths in the syntax diagram for DROP VIEW are tested by tests 1.*. # diff --git a/test/e_expr.test b/test/e_expr.test index 74d0c40..271635f 100644 --- a/test/e_expr.test +++ b/test/e_expr.test @@ -366,9 +366,9 @@ db collate reverse reverse_collate # EVIDENCE-OF: R-59577-33471 The COLLATE operator is a unary postfix # operator that assigns a collating sequence to an expression. # -# EVIDENCE-OF: R-23441-22541 The COLLATE operator has a higher -# precedence (binds more tightly) than any prefix unary operator or any -# binary operator. +# EVIDENCE-OF: R-36231-30731 The COLLATE operator has a higher +# precedence (binds more tightly) than any binary operator and any unary +# prefix operator except "~". # do_execsql_test e_expr-9.1 { SELECT 'abcd' < 'bbbb' COLLATE reverse } 0 do_execsql_test e_expr-9.2 { SELECT ('abcd' < 'bbbb') COLLATE reverse } 1 @@ -450,7 +450,7 @@ do_execsql_test e_expr-10.3.4 { SELECT typeof('isn''t') } {text} # containing hexadecimal data and preceded by a single "x" or "X" # character. # -# EVIDENCE-OF: R-39344-59787 For example: X'53514C697465' +# EVIDENCE-OF: R-19836-11244 Example: X'53514C697465' # do_execsql_test e_expr-10.4.1 { SELECT typeof(X'0123456789ABCDEF') } blob do_execsql_test e_expr-10.4.2 { SELECT typeof(x'0123456789ABCDEF') } blob @@ -631,7 +631,7 @@ do_test e_expr-11.7.1 { sqlite3_finalize $stmt } SQLITE_OK #------------------------------------------------------------------------- # "Test" the syntax diagrams in lang_expr.html. # -# EVIDENCE-OF: R-02989-21050 -- syntax diagram signed-number +# -- syntax diagram signed-number # do_execsql_test e_expr-12.1.1 { SELECT 0, +0, -0 } {0 0 0} do_execsql_test e_expr-12.1.2 { SELECT 1, +1, -1 } {1 1 -1} @@ -646,7 +646,7 @@ do_execsql_test e_expr-12.1.6 { SELECT 0.0001, +0.0001, -0.0001 } {0.0001 0.0001 -0.0001} -# EVIDENCE-OF: R-43188-60852 -- syntax diagram literal-value +# -- syntax diagram literal-value # set sqlite_current_time 1 do_execsql_test e_expr-12.2.1 {SELECT 123} {123} @@ -659,7 +659,7 @@ do_execsql_test e_expr-12.2.7 {SELECT CURRENT_DATE} {1970-01-01} do_execsql_test e_expr-12.2.8 {SELECT CURRENT_TIMESTAMP} {{1970-01-01 00:00:01}} set sqlite_current_time 0 -# EVIDENCE-OF: R-50544-32159 -- syntax diagram expr +# -- syntax diagram expr # forcedelete test.db2 execsql { @@ -816,7 +816,7 @@ foreach {tn expr} { } } -# EVIDENCE-OF: R-39820-63916 -- syntax diagram raise-function +# -- syntax diagram raise-function # foreach {tn raiseexpr} { 1 "RAISE(IGNORE)" @@ -1081,9 +1081,9 @@ ifcapable !icu { # EVIDENCE-OF: R-33693-50180 The REGEXP operator is a special syntax for # the regexp() user function. # -# EVIDENCE-OF: R-57289-13578 If a application-defined SQL function named -# "regexp" is added at run-time, that function will be called in order -# to implement the REGEXP operator. +# EVIDENCE-OF: R-65524-61849 If an application-defined SQL function +# named "regexp" is added at run-time, then the "X REGEXP Y" operator +# will be implemented as a call to "regexp(Y,X)". # proc regexpfunc {args} { eval lappend ::regexpargs $args @@ -1294,7 +1294,7 @@ proc rev {str} { set ret } proc reverse {lhs rhs} { - string compare [rev $lhs] [ref $rhs] + string compare [rev $lhs] [rev $rhs] } db collate reverse reverse do_execsql_test e_expr-23.1.1 { @@ -1317,7 +1317,7 @@ do_execsql_test e_expr-23.1.4 { } {B} do_execsql_test e_expr-23.1.5 { SELECT CASE b WHEN a THEN 'A' ELSE 'B' END FROM t1 -} {A} +} {B} do_execsql_test e_expr-23.1.6 { SELECT CASE 55 WHEN '55' THEN 'A' ELSE 'B' END } {B} @@ -1407,10 +1407,12 @@ do_test e_expr-26.1.6 { set ::evalcount } {5} #------------------------------------------------------------------------- # Test statements related to CAST expressions. # -# EVIDENCE-OF: R-65079-31758 Application of a CAST expression is -# different to application of a column affinity, as with a CAST -# expression the storage class conversion is forced even if it is lossy -# and irrreversible. +# EVIDENCE-OF: R-20854-17109 A CAST conversion is similar to the +# conversion that takes place when a column affinity is applied to a +# value except that with the CAST operator the conversion always takes +# place even if the conversion lossy and irreversible, whereas column +# affinity only changes the data type of a value if the change is +# lossless and reversible. # do_execsql_test e_expr-27.1.1 { CREATE TABLE t3(a TEXT, b REAL, c INTEGER); @@ -1594,26 +1596,36 @@ do_expr_test e_expr-30.4.1 { CAST('' AS INTEGER) } integer 0 do_expr_test e_expr-30.4.2 { CAST('not a number' AS INTEGER) } integer 0 do_expr_test e_expr-30.4.3 { CAST('XXI' AS INTEGER) } integer 0 -# EVIDENCE-OF: R-00741-38776 A cast of a REAL value into an INTEGER will -# truncate the fractional part of the REAL. +# EVIDENCE-OF: R-08980-53124 The CAST operator understands decimal +# integers only — conversion of hexadecimal integers stops at +# the "x" in the "0x" prefix of the hexadecimal integer string and thus +# result of the CAST is always zero. +do_expr_test e_expr-30.5.1 { CAST('0x1234' AS INTEGER) } integer 0 +do_expr_test e_expr-30.5.2 { CAST('0X1234' AS INTEGER) } integer 0 + +# EVIDENCE-OF: R-02752-50091 A cast of a REAL value into an INTEGER +# results in the integer between the REAL value and zero that is closest +# to the REAL value. # do_expr_test e_expr-31.1.1 { CAST(3.14159 AS INTEGER) } integer 3 do_expr_test e_expr-31.1.2 { CAST(1.99999 AS INTEGER) } integer 1 do_expr_test e_expr-31.1.3 { CAST(-1.99999 AS INTEGER) } integer -1 do_expr_test e_expr-31.1.4 { CAST(-0.99999 AS INTEGER) } integer 0 -# EVIDENCE-OF: R-49503-28105 If a REAL is too large to be represented as -# an INTEGER then the result of the cast is the largest negative -# integer: -9223372036854775808. +# EVIDENCE-OF: R-51517-40824 If a REAL is greater than the greatest +# possible signed integer (+9223372036854775807) then the result is the +# greatest possible signed integer and if the REAL is less than the +# least possible signed integer (-9223372036854775808) then the result +# is the least possible signed integer. # -do_expr_test e_expr-31.2.1 { CAST(2e+50 AS INT) } integer -9223372036854775808 +do_expr_test e_expr-31.2.1 { CAST(2e+50 AS INT) } integer 9223372036854775807 do_expr_test e_expr-31.2.2 { CAST(-2e+50 AS INT) } integer -9223372036854775808 do_expr_test e_expr-31.2.3 { CAST(-9223372036854775809.0 AS INT) } integer -9223372036854775808 do_expr_test e_expr-31.2.4 { CAST(9223372036854775809.0 AS INT) -} integer -9223372036854775808 +} integer 9223372036854775807 # EVIDENCE-OF: R-09295-61337 Casting a TEXT or BLOB value into NUMERIC @@ -1847,5 +1859,43 @@ foreach {tn expr} { do_expr_test e_expr-36.4.$tn $expr null {} } +# EVIDENCE-OF: R-62477-06476 For example, the values NULL, 0.0, 0, +# 'english' and '0' are all considered to be false. +# +do_execsql_test e_expr-37.1 { + SELECT CASE WHEN NULL THEN 'true' ELSE 'false' END; +} {false} +do_execsql_test e_expr-37.2 { + SELECT CASE WHEN 0.0 THEN 'true' ELSE 'false' END; +} {false} +do_execsql_test e_expr-37.3 { + SELECT CASE WHEN 0 THEN 'true' ELSE 'false' END; +} {false} +do_execsql_test e_expr-37.4 { + SELECT CASE WHEN 'engligh' THEN 'true' ELSE 'false' END; +} {false} +do_execsql_test e_expr-37.5 { + SELECT CASE WHEN '0' THEN 'true' ELSE 'false' END; +} {false} + +# EVIDENCE-OF: R-55532-10108 Values 1, 1.0, 0.1, -0.1 and '1english' are +# considered to be true. +# +do_execsql_test e_expr-37.6 { + SELECT CASE WHEN 1 THEN 'true' ELSE 'false' END; +} {true} +do_execsql_test e_expr-37.7 { + SELECT CASE WHEN 1.0 THEN 'true' ELSE 'false' END; +} {true} +do_execsql_test e_expr-37.8 { + SELECT CASE WHEN 0.1 THEN 'true' ELSE 'false' END; +} {true} +do_execsql_test e_expr-37.9 { + SELECT CASE WHEN -0.1 THEN 'true' ELSE 'false' END; +} {true} +do_execsql_test e_expr-37.10 { + SELECT CASE WHEN '1english' THEN 'true' ELSE 'false' END; +} {true} + finish_test diff --git a/test/e_fkey.test b/test/e_fkey.test index 001ba6c..0975650 100644 --- a/test/e_fkey.test +++ b/test/e_fkey.test @@ -135,9 +135,9 @@ reset_db # # This also tests that foreign key constraints are disabled by default. # -# EVIDENCE-OF: R-59578-04990 Foreign key constraints are disabled by +# EVIDENCE-OF: R-44261-39702 Foreign key constraints are disabled by # default (for backwards compatibility), so must be enabled separately -# for each database connection separately. +# for each database connection. # drop_all_tables do_test e_fkey-4.1 { @@ -163,9 +163,10 @@ do_test e_fkey-4.2 { } {world} #------------------------------------------------------------------------- -# EVIDENCE-OF: R-15278-54456 The application can can also use a PRAGMA +# EVIDENCE-OF: R-08013-37737 The application can also use a PRAGMA # foreign_keys statement to determine if foreign keys are currently # enabled. + # # This also tests the example code in section 2 of foreignkeys.in. # @@ -211,7 +212,7 @@ do_test e_fkey-6.1 { catchsql { DELETE FROM t1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-6.2 { execsql { PRAGMA foreign_keys } } {1} @@ -265,11 +266,11 @@ do_test e_fkey-7.1 { # do_test e_fkey-8.1 { catchsql { INSERT INTO track VALUES(1, 'track 1', 1) } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-8.2 { execsql { INSERT INTO artist VALUES(2, 'artist 1') } catchsql { INSERT INTO track VALUES(1, 'track 1', 1) } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-8.2 { execsql { INSERT INTO track VALUES(1, 'track 1', 2) } } {} @@ -283,7 +284,7 @@ do_test e_fkey-8.2 { # do_test e_fkey-9.1 { catchsql { DELETE FROM artist WHERE artistid = 2 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-9.2 { execsql { DELETE FROM track WHERE trackartist = 2; @@ -311,14 +312,14 @@ do_test e_fkey-10.2 { do_test e_fkey-10.3 { # Setting the trackid to a non-NULL value fails, of course. catchsql { UPDATE track SET trackartist = 5 WHERE trackid = 1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-10.4 { execsql { INSERT INTO artist VALUES(5, 'artist 5'); UPDATE track SET trackartist = 5 WHERE trackid = 1; } catchsql { DELETE FROM artist WHERE artistid = 5} -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-10.5 { execsql { UPDATE track SET trackartist = NULL WHERE trackid = 1; @@ -344,8 +345,8 @@ proc test_r52486_21352 {tn sql} { set res [catchsql $sql] set results { {0 {}} - {1 {PRIMARY KEY must be unique}} - {1 {foreign key constraint failed}} + {1 {UNIQUE constraint failed: artist.artistid}} + {1 {FOREIGN KEY constraint failed}} } if {[lsearch $results $res]<0} { error $res @@ -409,7 +410,7 @@ do_test e_fkey-12.1 { } {} do_test e_fkey-12.2 { catchsql { INSERT INTO track VALUES(14, 'Mr. Bojangles', NULL) } -} {1 {track.trackartist may not be NULL}} +} {1 {NOT NULL constraint failed: track.trackartist}} #------------------------------------------------------------------------- # EVIDENCE-OF: R-16127-35442 @@ -438,7 +439,7 @@ do_test e_fkey-13.1 { } {} do_test e_fkey-13.2 { catchsql { INSERT INTO track VALUES(14, 'Mr. Bojangles', 3) } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-13.3 { execsql { INSERT INTO track VALUES(14, 'Mr. Bojangles', NULL) } } {} @@ -446,7 +447,7 @@ do_test e_fkey-13.4 { catchsql { UPDATE track SET trackartist = 3 WHERE trackname = 'Mr. Bojangles'; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-13.5 { execsql { INSERT INTO artist VALUES(3, 'Sammy Davis Jr.'); @@ -464,7 +465,7 @@ do_test e_fkey-14.1 { catchsql { DELETE FROM artist WHERE artistname = 'Frank Sinatra'; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-14.2 { execsql { DELETE FROM track WHERE trackname = 'My Way'; @@ -475,7 +476,7 @@ do_test e_fkey-14.3 { catchsql { UPDATE artist SET artistid=4 WHERE artistname = 'Dean Martin'; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-14.4 { execsql { DELETE FROM track WHERE trackname IN('That''s Amore', 'Christmas Blues'); @@ -513,7 +514,7 @@ do_test e_fkey-15.1 { proc test_efkey_45 {tn isError sql} { do_test e_fkey-15.$tn.1 " catchsql {$sql} - " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] + " [lindex {{0 {}} {1 {FOREIGN KEY constraint failed}}} $isError] do_test e_fkey-15.$tn.2 { execsql { @@ -557,10 +558,10 @@ do_test e_fkey-16.2 { } {} do_test e_fkey-16.3 { catchsql { UPDATE t2 SET b = 'two' WHERE rowid = 1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-16.4 { catchsql { DELETE FROM t1 WHERE rowid = 1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} #------------------------------------------------------------------------- # Specifically, test that when comparing child and parent key values the @@ -592,7 +593,7 @@ do_test e_fkey-17.3 { } {integer integer text} do_test e_fkey-17.4 { catchsql { DELETE FROM t1 WHERE rowid = 2 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} ########################################################################### ### SECTION 3: Required and Suggested Database Indexes @@ -896,7 +897,7 @@ do_test e_fkey-23.1 { proc test_efkey_60 {tn isError sql} { do_test e_fkey-23.$tn " catchsql {$sql} - " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] + " [lindex {{0 {}} {1 {FOREIGN KEY constraint failed}}} $isError] } test_efkey_60 2 1 "INSERT INTO c1 VALUES(239, 231)" @@ -933,7 +934,7 @@ do_test e_fkey-24.1 { proc test_efkey_61 {tn isError sql} { do_test e_fkey-24.$tn " catchsql {$sql} - " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] + " [lindex {{0 {}} {1 {FOREIGN KEY constraint failed}}} $isError] } foreach {tn c} [list 2 c1 3 c2 4 c3] { test_efkey_61 $tn.1 1 "INSERT INTO $c VALUES(1, 2)" @@ -974,15 +975,15 @@ do_execsql_test e_fkey-25.2 { EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?; } { - 0 0 0 {SCAN TABLE artist (~1000000 rows)} - 0 0 0 {SCAN TABLE track (~100000 rows)} + 0 0 0 {SCAN TABLE artist} + 0 0 0 {SCAN TABLE track} } do_execsql_test e_fkey-25.3 { PRAGMA foreign_keys = ON; EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; } { - 0 0 0 {SCAN TABLE artist (~1000000 rows)} - 0 0 0 {SCAN TABLE track (~100000 rows)} + 0 0 0 {SCAN TABLE artist} + 0 0 0 {SCAN TABLE track} } do_test e_fkey-25.4 { execsql { @@ -998,7 +999,7 @@ do_test e_fkey-25.5 { concat \ [execsql { SELECT rowid FROM track WHERE trackartist = 5 }] \ [catchsql { DELETE FROM artist WHERE artistid = 5 }] -} {1 1 {foreign key constraint failed}} +} {1 1 {FOREIGN KEY constraint failed}} do_test e_fkey-25.6 { concat \ @@ -1010,7 +1011,7 @@ do_test e_fkey-25.7 { concat \ [execsql { SELECT rowid FROM track WHERE trackartist = 6 }] \ [catchsql { DELETE FROM artist WHERE artistid = 6 }] -} {2 1 {foreign key constraint failed}} +} {2 1 {FOREIGN KEY constraint failed}} #------------------------------------------------------------------------- # EVIDENCE-OF: R-47936-10044 Or, more generally: @@ -1099,15 +1100,15 @@ do_test e_fkey-27.2 { do_execsql_test e_fkey-27.3 { EXPLAIN QUERY PLAN UPDATE artist SET artistid = ?, artistname = ? } { - 0 0 0 {SCAN TABLE artist (~1000000 rows)} - 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)} - 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)} + 0 0 0 {SCAN TABLE artist} + 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} + 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} } do_execsql_test e_fkey-27.4 { EXPLAIN QUERY PLAN DELETE FROM artist } { - 0 0 0 {SCAN TABLE artist (~1000000 rows)} - 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)} + 0 0 0 {SCAN TABLE artist} + 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} } @@ -1199,7 +1200,7 @@ do_test e_fkey-29.3 { catchsql { INSERT INTO song VALUES(2, 'Elvis Presley', 'Elvis Is Back!', 'Fever'); } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} #------------------------------------------------------------------------- @@ -1240,7 +1241,7 @@ do_test e_fkey-31.1 { do_test e_fkey-31.2 { # Execute a statement that violates the immediate FK constraint. catchsql { INSERT INTO prince VALUES(1, 2) } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-31.3 { # This time, use a trigger to fix the constraint violation before the @@ -1265,7 +1266,7 @@ do_test e_fkey-31.4 { DROP TRIGGER kt; } catchsql { INSERT INTO prince VALUES(3, 4) } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-31.5 { execsql { COMMIT; @@ -1296,7 +1297,7 @@ do_test e_fkey-31.5 { proc test_efkey_34 {tn isError sql} { do_test e_fkey-32.$tn " catchsql {$sql} - " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] + " [lindex {{0 {}} {1 {FOREIGN KEY constraint failed}}} $isError] } drop_all_tables @@ -1327,7 +1328,7 @@ drop_all_tables proc test_efkey_35 {tn isError sql} { do_test e_fkey-33.$tn " catchsql {$sql} - " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] + " [lindex {{0 {}} {1 {FOREIGN KEY constraint failed}}} $isError] } do_test e_fkey-33.1 { execsql { @@ -1417,7 +1418,7 @@ do_test e_fkey-34.1 { proc test_efkey_29 {tn sql isError} { do_test e_fkey-34.$tn "catchsql {$sql}" [ - lindex {{0 {}} {1 {foreign key constraint failed}}} $isError + lindex {{0 {}} {1 {FOREIGN KEY constraint failed}}} $isError ] } test_efkey_29 2 "BEGIN" 0 @@ -1491,7 +1492,7 @@ do_test e_fkey-35.2 { INSERT INTO track VALUES(1, 'White Christmas', 5); } catchsql COMMIT -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-35.3 { execsql { INSERT INTO artist VALUES(5, 'Bing Crosby'); @@ -1528,7 +1529,7 @@ do_test e_fkey-36.2 { } {} do_test e_fkey-36.3 { catchsql COMMIT -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-36.4 { execsql { UPDATE t1 SET a = 5 WHERE a = 4; @@ -1558,7 +1559,7 @@ do_test e_fkey-37.1 { } {} do_test e_fkey-37.2 { catchsql {RELEASE one} -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-37.3 { execsql { UPDATE t1 SET a = 7 WHERE a = 6; @@ -1575,7 +1576,7 @@ do_test e_fkey-37.4 { } {} do_test e_fkey-37.5 { catchsql {RELEASE one} -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-37.6 { execsql {ROLLBACK TO one ; RELEASE one} } {} @@ -1606,7 +1607,7 @@ do_test e_fkey-38.2 { } {1 1 2 2 3 3 4 4 5 6} do_test e_fkey-38.3 { catchsql COMMIT -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-38.4 { execsql { ROLLBACK TO one; @@ -1627,11 +1628,11 @@ do_test e_fkey-38.5 { } {} do_test e_fkey-38.6 { catchsql {RELEASE a} -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-38.7 { execsql {ROLLBACK TO c} catchsql {RELEASE a} -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-38.8 { execsql { ROLLBACK TO b; @@ -1782,7 +1783,7 @@ do_test e_fkey-41.2 { } {j k l m} do_test e_fkey-41.3 { catchsql COMMIT -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-41.4 { execsql ROLLBACK } {} @@ -1820,10 +1821,10 @@ do_test e_fkey-41.2 { } {} do_test e_fkey-41.3 { catchsql { DELETE FROM parent WHERE p1 = 'a' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-41.4 { catchsql { UPDATE parent SET p2 = 'e' WHERE p1 = 'c' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} #------------------------------------------------------------------------- # Test that RESTRICT is slightly different from NO ACTION for IMMEDIATE @@ -1857,7 +1858,7 @@ do_test e_fkey-42.1 { } {} do_test e_fkey-42.2 { catchsql { UPDATE parent SET x = 'key one' WHERE x = 'key1' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-42.3 { execsql { UPDATE parent SET x = 'key two' WHERE x = 'key2'; @@ -1885,7 +1886,7 @@ do_test e_fkey-42.4 { } {} do_test e_fkey-42.5 { catchsql { DELETE FROM parent WHERE x = 'key1' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-42.6 { execsql { DELETE FROM parent WHERE x = 'key2'; @@ -1908,7 +1909,7 @@ do_test e_fkey-42.7 { } {} do_test e_fkey-42.8 { catchsql { REPLACE INTO parent VALUES('key1') } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-42.9 { execsql { REPLACE INTO parent VALUES('key2'); @@ -1944,13 +1945,13 @@ do_test e_fkey-43.1 { } {} do_test e_fkey-43.2 { catchsql { UPDATE parent SET x = 'key one' WHERE x = 'key1' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-43.3 { execsql { UPDATE parent SET x = 'key two' WHERE x = 'key2' } } {} do_test e_fkey-43.4 { catchsql COMMIT -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-43.5 { execsql { UPDATE child2 SET c = 'key two'; @@ -1978,13 +1979,13 @@ do_test e_fkey-43.6 { } {} do_test e_fkey-43.7 { catchsql { DELETE FROM parent WHERE x = 'key1' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-43.8 { execsql { DELETE FROM parent WHERE x = 'key2' } } {} do_test e_fkey-43.9 { catchsql COMMIT -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-43.10 { execsql { UPDATE child2 SET c = NULL; @@ -2240,7 +2241,7 @@ do_test e_fkey-49.3 { } {ONE two three} do_test e_fkey-49.4 { catchsql { UPDATE parent SET a = '' WHERE a = 'oNe' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} #------------------------------------------------------------------------- @@ -2275,7 +2276,7 @@ do_test e_fkey-50.1 { } {} do_test e_fkey-50.2 { catchsql { DELETE FROM artist WHERE artistname = 'Sammy Davis Jr.' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-50.3 { execsql { INSERT INTO artist VALUES(0, 'Unknown Artist'); @@ -2639,7 +2640,7 @@ do_test e_fkey-58.1 { } execsql { INSERT INTO c5 VALUES('a', 'b') } catchsql { DROP TABLE p } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-58.2 { execsql { SELECT * FROM p } } {a b} @@ -2648,7 +2649,7 @@ do_test e_fkey-58.3 { BEGIN; DROP TABLE p; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-58.4 { execsql { SELECT * FROM p; @@ -2682,11 +2683,11 @@ do_test e_fkey-59.2 { } {} do_test e_fkey-59.3 { catchsql COMMIT -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-59.4 { execsql { CREATE TABLE p(a, b, PRIMARY KEY(a, b)) } catchsql COMMIT -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-59.5 { execsql { INSERT INTO p VALUES('a', 'b') } execsql COMMIT @@ -2849,7 +2850,7 @@ foreach zMatch [list SIMPLE PARTIAL FULL Simple parTIAL FuLL ] { # Check that the FK is enforced properly if there are no NULL values # in the child key columns. catchsql { INSERT INTO c VALUES('a', 2, 4) } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} } #------------------------------------------------------------------------- @@ -2879,13 +2880,13 @@ do_test e_fkey-62.3 { } {} do_test e_fkey-62.4 { catchsql { INSERT INTO ci VALUES('x', 'y') } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-62.5 { catchsql { INSERT INTO cd VALUES('x', 'y') } } {0 {}} do_test e_fkey-62.6 { catchsql { COMMIT } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test e_fkey-62.7 { execsql { DELETE FROM cd; @@ -2946,45 +2947,52 @@ proc test_on_update_recursion {limit} { " } -do_test e_fkey-63.1.1 { - test_on_delete_recursion $SQLITE_MAX_TRIGGER_DEPTH -} {0 0} -do_test e_fkey-63.1.2 { - test_on_delete_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1] -} {1 {too many levels of trigger recursion}} -do_test e_fkey-63.1.3 { - sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5 - test_on_delete_recursion 5 -} {0 0} -do_test e_fkey-63.1.4 { - test_on_delete_recursion 6 -} {1 {too many levels of trigger recursion}} -do_test e_fkey-63.1.5 { - sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000 -} {5} -do_test e_fkey-63.2.1 { - test_on_update_recursion $SQLITE_MAX_TRIGGER_DEPTH -} {0 0} -do_test e_fkey-63.2.2 { - test_on_update_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1] -} {1 {too many levels of trigger recursion}} -do_test e_fkey-63.2.3 { - sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5 - test_on_update_recursion 5 -} {0 0} -do_test e_fkey-63.2.4 { - test_on_update_recursion 6 -} {1 {too many levels of trigger recursion}} -do_test e_fkey-63.2.5 { - sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000 -} {5} +# If the current build was created using clang with the -fsanitize=address +# switch, then the library uses considerably more stack space than usual. +# So much more, that some of the following tests cause stack overflows +# if they are run under this configuration. +# +if {[clang_sanitize_address]==0} { + do_test e_fkey-63.1.1 { + test_on_delete_recursion $SQLITE_MAX_TRIGGER_DEPTH + } {0 0} + do_test e_fkey-63.1.2 { + test_on_delete_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1] + } {1 {too many levels of trigger recursion}} + do_test e_fkey-63.1.3 { + sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5 + test_on_delete_recursion 5 + } {0 0} + do_test e_fkey-63.1.4 { + test_on_delete_recursion 6 + } {1 {too many levels of trigger recursion}} + do_test e_fkey-63.1.5 { + sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000 + } {5} + do_test e_fkey-63.2.1 { + test_on_update_recursion $SQLITE_MAX_TRIGGER_DEPTH + } {0 0} + do_test e_fkey-63.2.2 { + test_on_update_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1] + } {1 {too many levels of trigger recursion}} + do_test e_fkey-63.2.3 { + sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5 + test_on_update_recursion 5 + } {0 0} + do_test e_fkey-63.2.4 { + test_on_update_recursion 6 + } {1 {too many levels of trigger recursion}} + do_test e_fkey-63.2.5 { + sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000 + } {5} +} #------------------------------------------------------------------------- # The setting of the recursive_triggers pragma does not affect foreign # key actions. # -# EVIDENCE-OF: R-51769-32730 The PRAGMA recursive_triggers setting does -# not not affect the operation of foreign key actions. +# EVIDENCE-OF: R-44355-00270 The PRAGMA recursive_triggers setting does +# not affect the operation of foreign key actions. # foreach recursive_triggers_setting [list 0 1 ON OFF] { drop_all_tables diff --git a/test/e_insert.test b/test/e_insert.test index 951ae24..0ea4b76 100644 --- a/test/e_insert.test +++ b/test/e_insert.test @@ -50,7 +50,7 @@ proc do_insert_tests {args} { uplevel do_select_tests $args } -# EVIDENCE-OF: R-21350-31508 -- syntax diagram insert-stmt +# -- syntax diagram insert-stmt # do_insert_tests e_insert-0 { 1 "INSERT INTO a1 DEFAULT VALUES" {} @@ -174,9 +174,9 @@ do_insert_tests e_insert-1.2 -error { 4 "INSERT INTO a2 VALUES(1,2,3,4,5)" {a2 3 5} } -# EVIDENCE-OF: R-34231-22576 In this case the result of evaluating the -# left-most expression in each term of the VALUES list is inserted into -# the left-most column of the each new row, and forth for each +# EVIDENCE-OF: R-29730-42609 In this case the result of evaluating the +# left-most expression from each term of the VALUES list is inserted +# into the left-most column of each new row, and so forth for each # subsequent expression. # delete_all_data @@ -191,8 +191,8 @@ do_insert_tests e_insert-1.3 { 3b "SELECT * FROM a2 WHERE oid=last_insert_rowid()" {2 x y} } -# EVIDENCE-OF: R-44710-64652 If a column-list is specified, then the -# number of values in each term of the VALUS list must match the number +# EVIDENCE-OF: R-09234-17933 If a column-list is specified, then the +# number of values in each term of the VALUE list must match the number # of specified columns. # do_insert_tests e_insert-1.4 -error { @@ -371,22 +371,22 @@ do_execsql_test e_insert-4.1.0 { INSERT INTO a4 VALUES(3, 'a'); } {} foreach {tn sql error ac data } { - 1.1 "INSERT INTO a4 VALUES(2,'b')" {column c is not unique} 1 {1 a 2 a 3 a} + 1.1 "INSERT INTO a4 VALUES(2,'b')" {UNIQUE constraint failed: a4.c} 1 {1 a 2 a 3 a} 1.2 "INSERT OR REPLACE INTO a4 VALUES(2, 'b')" {} 1 {1 a 3 a 2 b} 1.3 "INSERT OR IGNORE INTO a4 VALUES(3, 'c')" {} 1 {1 a 3 a 2 b} 1.4 "BEGIN" {} 0 {1 a 3 a 2 b} - 1.5 "INSERT INTO a4 VALUES(1, 'd')" {column c is not unique} 0 {1 a 3 a 2 b} + 1.5 "INSERT INTO a4 VALUES(1, 'd')" {UNIQUE constraint failed: a4.c} 0 {1 a 3 a 2 b} 1.6 "INSERT OR ABORT INTO a4 VALUES(1, 'd')" - {column c is not unique} 0 {1 a 3 a 2 b} + {UNIQUE constraint failed: a4.c} 0 {1 a 3 a 2 b} 1.7 "INSERT OR ROLLBACK INTO a4 VALUES(1, 'd')" - {column c is not unique} 1 {1 a 3 a 2 b} + {UNIQUE constraint failed: a4.c} 1 {1 a 3 a 2 b} 1.8 "INSERT INTO a4 SELECT 4, 'e' UNION ALL SELECT 3, 'e'" - {column c is not unique} 1 {1 a 3 a 2 b} + {UNIQUE constraint failed: a4.c} 1 {1 a 3 a 2 b} 1.9 "INSERT OR FAIL INTO a4 SELECT 4, 'e' UNION ALL SELECT 3, 'e'" - {column c is not unique} 1 {1 a 3 a 2 b 4 e} + {UNIQUE constraint failed: a4.c} 1 {1 a 3 a 2 b 4 e} 2.1 "INSERT INTO a4 VALUES(2,'f')" - {column c is not unique} 1 {1 a 3 a 2 b 4 e} + {UNIQUE constraint failed: a4.c} 1 {1 a 3 a 2 b 4 e} 2.2 "REPLACE INTO a4 VALUES(2, 'f')" {} 1 {1 a 3 a 4 e 2 f} } { do_catchsql_test e_insert-4.1.$tn.1 $sql [list [expr {$error!=""}] $error] diff --git a/test/e_reindex.test b/test/e_reindex.test index b39f37e..4b86787 100644 --- a/test/e_reindex.test +++ b/test/e_reindex.test @@ -26,7 +26,7 @@ do_execsql_test e_reindex-0.0 { CREATE INDEX i2 ON t1(b, a); } {} -# EVIDENCE-OF: R-51477-38549 -- syntax diagram reindex-stmt +# -- syntax diagram reindex-stmt # do_reindex_tests e_reindex-0.1 { 1 "REINDEX" {} @@ -67,10 +67,10 @@ sqlite3 db test.db do_execsql_test e_reindex-1.3 { PRAGMA integrity_check; } [list \ - {rowid 4 missing from index i2} \ - {rowid 4 missing from index i1} \ - {rowid 5 missing from index i2} \ - {rowid 5 missing from index i1} \ + {row 3 missing from index i2} \ + {row 3 missing from index i1} \ + {row 4 missing from index i2} \ + {row 4 missing from index i1} \ {wrong # of entries in index i2} \ {wrong # of entries in index i1} ] @@ -98,7 +98,7 @@ proc sort_by_length {lhs rhs} { array set V {one 1 two 2 three 3 four 4 five 5 six 6 seven 7 eight 8} proc sort_by_value {lhs rhs} { global V - set res [expr {$V($lhs) - $V(rhs)}] + set res [expr {$V($lhs) - $V($rhs)}] if {$res!=0} {return $res} return [string compare $lhs $rhs] } diff --git a/test/e_select.test b/test/e_select.test index ea44aed..89d61b5 100644 --- a/test/e_select.test +++ b/test/e_select.test @@ -83,7 +83,7 @@ proc do_join_test {tn select res} { # The following tests check that all paths on the syntax diagrams on # the lang_select.html page may be taken. # -# EVIDENCE-OF: R-11353-33501 -- syntax diagram join-constraint +# -- syntax diagram join-constraint # do_join_test e_select-0.1.1 { SELECT count(*) FROM t1 %JOIN% t2 ON (t1.a=t2.a) @@ -101,7 +101,7 @@ do_catchsql_test e_select-0.1.5 { SELECT count(*) FROM t1, t2 USING (a) ON (t1.a=t2.a) } {1 {near "ON": syntax error}} -# EVIDENCE-OF: R-40919-40941 -- syntax diagram select-core +# -- syntax diagram select-core # # 0: SELECT ... # 1: SELECT DISTINCT ... @@ -226,7 +226,7 @@ do_select_tests e_select-0.2 { } -# EVIDENCE-OF: R-41378-26734 -- syntax diagram result-column +# -- syntax diagram result-column # do_select_tests e_select-0.3 { 1 "SELECT * FROM t1" {a one b two c three} @@ -236,9 +236,9 @@ do_select_tests e_select-0.3 { 5 "SELECT 'x'||a||'x' AS alias FROM t1" {xax xbx xcx} } -# EVIDENCE-OF: R-43129-35648 -- syntax diagram join-source +# -- syntax diagram join-source # -# EVIDENCE-OF: R-36683-37460 -- syntax diagram join-op +# -- syntax diagram join-op # do_select_tests e_select-0.4 { 1 "SELECT t1.rowid FROM t1" {1 2 3} @@ -263,7 +263,7 @@ do_select_tests e_select-0.4 { 16 "SELECT t1.rowid FROM t1 CROSS JOIN t3" {1 1 2 2 3 3} } -# EVIDENCE-OF: R-28308-37813 -- syntax diagram compound-operator +# -- syntax diagram compound-operator # do_select_tests e_select-0.5 { 1 "SELECT rowid FROM t1 UNION ALL SELECT rowid+2 FROM t4" {1 2 3 3 4} @@ -272,7 +272,7 @@ do_select_tests e_select-0.5 { 4 "SELECT rowid FROM t1 EXCEPT SELECT rowid+2 FROM t4" {1 2} } -# EVIDENCE-OF: R-06480-34950 -- syntax diagram ordering-term +# -- syntax diagram ordering-term # do_select_tests e_select-0.6 { 1 "SELECT b||a FROM t1 ORDER BY b||a" {onea threec twob} @@ -281,7 +281,7 @@ do_select_tests e_select-0.6 { 4 "SELECT b||a FROM t1 ORDER BY (b||a) DESC" {twob threec onea} } -# EVIDENCE-OF: R-23926-36668 -- syntax diagram select-stmt +# -- syntax diagram select-stmt # do_select_tests e_select-0.7 { 1 "SELECT * FROM t1" {a one b two c three} @@ -333,9 +333,9 @@ do_select_tests e_select-1.1 { 6 "SELECT count(*) WHERE 1" {1} } -# EVIDENCE-OF: R-48114-33255 If there is only a single table in the -# join-source following the FROM clause, then the input data used by the -# SELECT statement is the contents of the named table. +# EVIDENCE-OF: R-45424-07352 If there is only a single table or subquery +# in the FROM clause, then the input data used by the SELECT statement +# is the contents of the named table. # # The results of the SELECT queries suggest that they are operating on the # contents of the table 'xx'. @@ -357,10 +357,10 @@ do_select_tests e_select-1.2 { 3 "SELECT sum(x), sum(y) FROM xx" {-17.89 -16.87} } -# EVIDENCE-OF: R-23593-12456 If there is more than one table specified -# as part of the join-source following the FROM keyword, then the -# contents of each named table are joined into a single dataset for the -# simple SELECT statement to operate on. +# EVIDENCE-OF: R-28355-09804 If there is more than one table or subquery +# in FROM clause then the contents of all tables and/or subqueries are +# joined into a single dataset for the simple SELECT statement to +# operate on. # # There are more detailed tests for subsequent requirements that add # more detail to this idea. We just add a single test that shows that @@ -383,10 +383,10 @@ do_select_tests e_select-1.3 { # of cartesian joins in the SELECT documentation is consistent with SQLite. # In doing so, we test the following three requirements as a side-effect: # -# EVIDENCE-OF: R-46122-14930 If the join-op is "CROSS JOIN", "INNER -# JOIN", "JOIN" or a comma (",") and there is no ON or USING clause, -# then the result of the join is simply the cartesian product of the -# left and right-hand datasets. +# EVIDENCE-OF: R-49872-03192 If the join-operator is "CROSS JOIN", +# "INNER JOIN", "JOIN" or a comma (",") and there is no ON or USING +# clause, then the result of the join is simply the cartesian product of +# the left and right-hand datasets. # # The tests are built on this assertion. Really, they test that the output # of a CROSS JOIN, JOIN, INNER JOIN or "," join matches the expected result @@ -395,8 +395,8 @@ do_select_tests e_select-1.3 { # EVIDENCE-OF: R-46256-57243 There is no difference between the "INNER # JOIN", "JOIN" and "," join operators. # -# EVIDENCE-OF: R-07544-24155 The "CROSS JOIN" join operator produces the -# same data as the "INNER JOIN", "JOIN" and "," operators +# EVIDENCE-OF: R-25071-21202 The "CROSS JOIN" join operator produces the +# same result as the "INNER JOIN", "JOIN" and "," operators # # All tests are run 4 times, with the only difference in each run being # which of the 4 equivalent cartesian product join operators are used. @@ -450,24 +450,24 @@ do_join_test e_select-1.4.1.4 { # left-hand and right-hand datasets. # do_join_test e_select-1.4.2.1 { - SELECT * FROM x2 %JOIN% x3 + SELECT * FROM x2 %JOIN% x3 ORDER BY +c, +f } [list -60.06 {} {} -39.24 {} encompass -1 \ - -60.06 {} {} presenting 51 reformation dignified \ - -60.06 {} {} conducting -87.24 37.56 {} \ - -60.06 {} {} coldest -96 dramatists 82.3 \ -60.06 {} {} alerting {} -93.79 {} \ + -60.06 {} {} coldest -96 dramatists 82.3 \ + -60.06 {} {} conducting -87.24 37.56 {} \ + -60.06 {} {} presenting 51 reformation dignified \ -58 {} 1.21 -39.24 {} encompass -1 \ - -58 {} 1.21 presenting 51 reformation dignified \ - -58 {} 1.21 conducting -87.24 37.56 {} \ - -58 {} 1.21 coldest -96 dramatists 82.3 \ -58 {} 1.21 alerting {} -93.79 {} \ + -58 {} 1.21 coldest -96 dramatists 82.3 \ + -58 {} 1.21 conducting -87.24 37.56 {} \ + -58 {} 1.21 presenting 51 reformation dignified \ ] # TODO: Come back and add a few more like the above. -# EVIDENCE-OF: R-20659-43267 In other words, if the left-hand dataset -# consists of Nlhs rows of Mlhs columns, and the right-hand dataset of -# Nrhs rows of Mrhs columns, then the cartesian product is a dataset of -# Nlhs.Nrhs rows, each containing Mlhs+Mrhs columns. +# EVIDENCE-OF: R-18439-38548 In other words, if the left-hand dataset +# consists of Nleft rows of Mleft columns, and the right-hand dataset of +# Nright rows of Mright columns, then the cartesian product is a dataset +# of Nleft×Nright rows, each containing Mleft+Mright columns. # # x1, x2 (Nlhs=3, Nrhs=2) (Mlhs=2, Mrhs=3) do_join_test e_select-1.4.3.1 { @@ -513,11 +513,10 @@ do_select_tests e_select-1.4.5 [list \ 4 { SELECT * FROM t1 AS y INNER JOIN t1 AS x } $t1_cross_t1 \ ] - -# EVIDENCE-OF: R-22775-56496 If there is an ON clause specified, then -# the ON expression is evaluated for each row of the cartesian product -# as a boolean expression. All rows for which the expression evaluates -# to false are excluded from the dataset. +# EVIDENCE-OF: R-38465-03616 If there is an ON clause then the ON +# expression is evaluated for each row of the cartesian product as a +# boolean expression. Only rows for which the expression evaluates to +# true are included from the dataset. # foreach {tn select res} [list \ 1 { SELECT * FROM t1 %JOIN% t2 ON (1) } $t1_cross_t2 \ @@ -540,9 +539,9 @@ foreach {tn select res} [list \ do_join_test e_select-1.3.$tn $select $res } -# EVIDENCE-OF: R-63358-54862 If there is a USING clause specified as -# part of the join-constraint, then each of the column names specified -# must exist in the datasets to both the left and right of the join-op. +# EVIDENCE-OF: R-49933-05137 If there is a USING clause then each of the +# column names specified must exist in the datasets to both the left and +# right of the join-operator. # do_select_tests e_select-1.4 -error { cannot join using column %s - column not present in both tables @@ -552,10 +551,10 @@ do_select_tests e_select-1.4 -error { 3 { SELECT * FROM t3, (SELECT a AS b, b AS c FROM t1) USING (a) } "a" } -# EVIDENCE-OF: R-55987-04584 For each pair of namesake columns, the +# EVIDENCE-OF: R-22776-52830 For each pair of named columns, the # expression "lhs.X = rhs.X" is evaluated for each row of the cartesian -# product as a boolean expression. All rows for which one or more of the -# expressions evaluates to false are excluded from the result set. +# product as a boolean expression. Only rows for which all such +# expressions evaluates to true are included from the result set. # do_select_tests e_select-1.5 { 1 { SELECT * FROM t1, t3 USING (a) } {a one 1 b two 2} @@ -566,8 +565,8 @@ do_select_tests e_select-1.5 { # USING clause, the normal rules for handling affinities, collation # sequences and NULL values in comparisons apply. # -# EVIDENCE-OF: R-35466-18578 The column from the dataset on the -# left-hand side of the join operator is considered to be on the +# EVIDENCE-OF: R-38422-04402 The column from the dataset on the +# left-hand side of the join-operator is considered to be on the # left-hand side of the comparison operator (=) for the purposes of # collation sequence and affinity precedence. # @@ -622,10 +621,9 @@ foreach {tn select res} { } { do_join_test e_select-1.7.$tn $select $res } - -# EVIDENCE-OF: R-41434-12448 If the join-op is a "LEFT JOIN" or "LEFT -# OUTER JOIN", then after the ON or USING filtering clauses have been -# applied, an extra row is added to the output for each row in the +# EVIDENCE-OF: R-42531-52874 If the join-operator is a "LEFT JOIN" or +# "LEFT OUTER JOIN", then after the ON or USING filtering clauses have +# been applied, an extra row is added to the output for each row in the # original left-hand input dataset that corresponds to no rows at all in # the composite dataset (if any). # @@ -660,8 +658,8 @@ do_select_tests e_select-1.9 { 2b "SELECT * FROM t7 LEFT JOIN t8 USING (a)" {x ex 24 abc 24 y why 25 {} {}} } -# EVIDENCE-OF: R-01809-52134 If the NATURAL keyword is added to any of -# the join-ops, then an implicit USING clause is added to the +# EVIDENCE-OF: R-04932-55942 If the NATURAL keyword is in the +# join-operator then an implicit USING clause is added to the # join-constraints. The implicit USING clause contains each of the # column names that appear in both the left and right-hand input # datasets. @@ -734,10 +732,10 @@ do_execsql_test e_select-3.0 { INSERT INTO x2 VALUES(7, 'mistrusted', 'standardized'); } {} -# EVIDENCE-OF: R-06999-14330 If a WHERE clause is specified, the WHERE +# EVIDENCE-OF: R-60775-64916 If a WHERE clause is specified, the WHERE # expression is evaluated for each row in the input data as a boolean -# expression. All rows for which the WHERE clause expression evaluates -# to false are excluded from the dataset before continuing. +# expression. Only rows for which the WHERE clause expression evaluates +# to true are included from the dataset before continuing. # do_execsql_test e_select-3.1.1 { SELECT k FROM x1 WHERE x } {3} do_execsql_test e_select-3.1.2 { SELECT k FROM x1 WHERE y } {3 5 6} @@ -815,8 +813,8 @@ do_select_tests e_select-4.1 { } } -# EVIDENCE-OF: R-61869-22578 It is an error to use a "*" or "alias.*" -# expression in any context other than than a result expression list. +# EVIDENCE-OF: R-38023-18396 It is an error to use a "*" or "alias.*" +# expression in any context other than a result expression list. # # EVIDENCE-OF: R-44324-41166 It is also an error to use a "*" or # "alias.*" expression in a simple SELECT query that does not have a @@ -1009,12 +1007,12 @@ do_execsql_test e_select-4.9.0 { INSERT INTO b3 VALUES('dEF', 'dEF'); } {} -# EVIDENCE-OF: R-57754-57109 If the SELECT statement is an aggregate +# EVIDENCE-OF: R-07284-35990 If the SELECT statement is an aggregate # query with a GROUP BY clause, then each of the expressions specified # as part of the GROUP BY clause is evaluated for each row of the # dataset. Each row is then assigned to a "group" based on the results; # rows for which the results of evaluating the GROUP BY expressions are -# the same are assigned to the same group. +# the same get assigned to the same group. # # These tests also show that the following is not untrue: # @@ -1226,7 +1224,7 @@ do_select_tests e_select-5.1 { # EVIDENCE-OF: R-08861-34280 If the simple SELECT is a SELECT ALL, then # the entire set of result rows are returned by the SELECT. # -# EVIDENCE-OF: R-47911-02086 If neither ALL or DISTINCT are present, +# EVIDENCE-OF: R-01256-01950 If neither ALL or DISTINCT are present, # then the behavior is as if ALL were specified. # # EVIDENCE-OF: R-14442-41305 If the simple SELECT is a SELECT DISTINCT, @@ -1373,8 +1371,9 @@ foreach {tn select op1 op2} { do_catchsql_test e_select-7.2.$tn $select [list 1 $err] } -# EVIDENCE-OF: R-22874-32655 ORDER BY and LIMIT clauses may only occur -# at the end of the entire compound SELECT. +# EVIDENCE-OF: R-45440-25633 ORDER BY and LIMIT clauses may only occur +# at the end of the entire compound SELECT, and then only if the final +# element of the compound is not a VALUES clause. # foreach {tn select} { 1 "SELECT * FROM j1 UNION ALL SELECT * FROM j2,j3 ORDER BY a" @@ -1386,6 +1385,7 @@ foreach {tn select} { 7 "SELECT * FROM j1 UNION SELECT * FROM j2,j3 ORDER BY a" 8 "SELECT count(*) FROM j1 UNION SELECT max(e) FROM j2 ORDER BY 1" + 8b "VALUES('8b') UNION SELECT max(e) FROM j2 ORDER BY 1" 9 "SELECT count(*), * FROM j1 UNION SELECT *,* FROM j2 ORDER BY 1,2,3" 10 "SELECT * FROM j1 UNION SELECT * FROM j2,j3 LIMIT 10" 11 "SELECT * FROM j1 UNION SELECT * FROM j2,j3 LIMIT 10 OFFSET 5" @@ -1407,6 +1407,14 @@ foreach {tn select} { } { do_test e_select-7.3.$tn { catch {execsql $select} msg } 0 } +foreach {tn select} { + 50 "SELECT * FROM j1 ORDER BY 1 UNION ALL SELECT * FROM j2,j3" + 51 "SELECT * FROM j1 LIMIT 1 UNION ALL SELECT * FROM j2,j3" + 52 "SELECT count(*) FROM j1 UNION ALL VALUES(11) ORDER BY 1" + 53 "SELECT count(*) FROM j1 UNION ALL VALUES(11) LIMIT 1" +} { + do_test e_select-7.3.$tn { catch {execsql $select} msg } 1 +} # EVIDENCE-OF: R-08531-36543 A compound SELECT created using UNION ALL # operator returns all the rows from the SELECT to the left of the UNION diff --git a/test/e_select2.test b/test/e_select2.test index b338d4f..8330894 100644 --- a/test/e_select2.test +++ b/test/e_select2.test @@ -344,16 +344,16 @@ foreach {tn indexes} { catchsql { DROP INDEX i3 } execsql $indexes - # EVIDENCE-OF: R-46122-14930 If the join-op is "CROSS JOIN", "INNER - # JOIN", "JOIN" or a comma (",") and there is no ON or USING clause, - # then the result of the join is simply the cartesian product of the - # left and right-hand datasets. + # EVIDENCE-OF: R-49872-03192 If the join-operator is "CROSS JOIN", + # "INNER JOIN", "JOIN" or a comma (",") and there is no ON or USING + # clause, then the result of the join is simply the cartesian product of + # the left and right-hand datasets. # # EVIDENCE-OF: R-46256-57243 There is no difference between the "INNER # JOIN", "JOIN" and "," join operators. # - # EVIDENCE-OF: R-07544-24155 The "CROSS JOIN" join operator produces the - # same data as the "INNER JOIN", "JOIN" and "," operators + # EVIDENCE-OF: R-25071-21202 The "CROSS JOIN" join operator produces the + # same result as the "INNER JOIN", "JOIN" and "," operators # test_join $tn.1.1 "t1, t2" {t1 t2} test_join $tn.1.2 "t1 INNER JOIN t2" {t1 t2} @@ -368,10 +368,10 @@ foreach {tn indexes} { test_join $tn.1.11 "t2 CROSS JOIN t2 AS x" {t2 t2} test_join $tn.1.12 "t2 JOIN t2 AS x" {t2 t2} - # EVIDENCE-OF: R-22775-56496 If there is an ON clause specified, then - # the ON expression is evaluated for each row of the cartesian product - # as a boolean expression. All rows for which the expression evaluates - # to false are excluded from the dataset. + # EVIDENCE-OF: R-38465-03616 If there is an ON clause then the ON + # expression is evaluated for each row of the cartesian product as a + # boolean expression. Only rows for which the expression evaluates to + # true are included from the dataset. # test_join $tn.2.1 "t1, t2 ON (t1.a=t2.a)" {t1 t2 -on {te_equals a a}} test_join $tn.2.2 "t2, t1 ON (t1.a=t2.a)" {t2 t1 -on {te_equals a a}} @@ -504,14 +504,14 @@ do_execsql_test e_select-2.2.0 { INSERT INTO t5 VALUES(2, 'two'); } {} -# EVIDENCE-OF: R-55824-40976 A sub-select specified in the join-source -# following the FROM clause in a simple SELECT statement is handled as -# if it was a table containing the data returned by executing the -# sub-select statement. +# EVIDENCE-OF: R-59237-46742 A subquery specified in the +# table-or-subquery following the FROM clause in a simple SELECT +# statement is handled as if it was a table containing the data returned +# by executing the subquery statement. # -# EVIDENCE-OF: R-42612-06757 Each column of the sub-select dataset -# inherits the collation sequence and affinity of the corresponding -# expression in the sub-select statement. +# EVIDENCE-OF: R-27438-53558 Each column of the subquery has the +# collation sequence and affinity of the corresponding expression in the +# subquery statement. # foreach {tn subselect select spec} { 1 "SELECT * FROM t2" "SELECT * FROM t1 JOIN %ss%" diff --git a/test/e_update.test b/test/e_update.test index 230c97f..e9c6b26 100644 --- a/test/e_update.test +++ b/test/e_update.test @@ -49,7 +49,7 @@ proc do_update_tests {args} { uplevel do_select_tests $args } -# EVIDENCE-OF: R-62337-45828 -- syntax diagram update-stmt +# -- syntax diagram update-stmt # do_update_tests e_update-0 { 1 "UPDATE t1 SET a=10" {} @@ -278,30 +278,30 @@ do_execsql_test e_update-1.8.0 { } {} foreach {tn sql error ac data } { 1 "UPDATE t3 SET b='one' WHERE a=3" - {column b is not unique} 1 {1 one 2 two 3 three 4 four} + {UNIQUE constraint failed: t3.b} 1 {1 one 2 two 3 three 4 four} 2 "UPDATE OR REPLACE t3 SET b='one' WHERE a=3" {} 1 {2 two 3 one 4 four} 3 "UPDATE OR FAIL t3 SET b='three'" - {column b is not unique} 1 {2 three 3 one 4 four} + {UNIQUE constraint failed: t3.b} 1 {2 three 3 one 4 four} 4 "UPDATE OR IGNORE t3 SET b='three' WHERE a=3" {} 1 {2 three 3 one 4 four} 5 "UPDATE OR ABORT t3 SET b='three' WHERE a=3" - {column b is not unique} 1 {2 three 3 one 4 four} + {UNIQUE constraint failed: t3.b} 1 {2 three 3 one 4 four} 6 "BEGIN" {} 0 {2 three 3 one 4 four} 7 "UPDATE t3 SET b='three' WHERE a=3" - {column b is not unique} 0 {2 three 3 one 4 four} + {UNIQUE constraint failed: t3.b} 0 {2 three 3 one 4 four} 8 "UPDATE OR ABORT t3 SET b='three' WHERE a=3" - {column b is not unique} 0 {2 three 3 one 4 four} + {UNIQUE constraint failed: t3.b} 0 {2 three 3 one 4 four} 9 "UPDATE OR FAIL t3 SET b='two'" - {column b is not unique} 0 {2 two 3 one 4 four} + {UNIQUE constraint failed: t3.b} 0 {2 two 3 one 4 four} 10 "UPDATE OR IGNORE t3 SET b='four' WHERE a=3" {} 0 {2 two 3 one 4 four} @@ -310,7 +310,7 @@ foreach {tn sql error ac data } { {} 0 {2 two 3 four} 12 "UPDATE OR ROLLBACK t3 SET b='four'" - {column b is not unique} 1 {2 three 3 one 4 four} + {UNIQUE constraint failed: t3.b} 1 {2 three 3 one 4 four} } { do_catchsql_test e_update-1.8.$tn.1 $sql [list [expr {$error!=""}] $error] do_execsql_test e_update-1.8.$tn.2 {SELECT * FROM t3} [list {*}$data] @@ -493,7 +493,7 @@ do_update_tests e_update-2.5 -error { # of the UPDATE statement is extended with optional ORDER BY and LIMIT # clauses # -# EVIDENCE-OF: R-45169-39597 -- syntax diagram update-stmt-limited +# -- syntax diagram update-stmt-limited # do_update_tests e_update-3.0 { 1 "UPDATE t1 SET a=b LIMIT 5" {} diff --git a/test/e_uri.test b/test/e_uri.test index ac34ed4..a8865ca 100644 --- a/test/e_uri.test +++ b/test/e_uri.test @@ -359,7 +359,7 @@ foreach {tn uri error} " # EVIDENCE-OF: R-49793-28525 Setting the cache parameter to "private" is # equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. # -# EVIDENCE-OF: R-19510-48080 If sqlite3_open_v2() is used and the +# EVIDENCE-OF: R-31773-41793 If sqlite3_open_v2() is used and the # "cache" parameter is present in a URI filename, its value overrides # any behavior requested by setting SQLITE_OPEN_PRIVATECACHE or # SQLITE_OPEN_SHAREDCACHE flag. diff --git a/test/e_vacuum.test b/test/e_vacuum.test index bad12d3..99b31aa 100644 --- a/test/e_vacuum.test +++ b/test/e_vacuum.test @@ -65,7 +65,7 @@ proc fragment_count {name} { } -# EVIDENCE-OF: R-45173-45977 -- syntax diagram vacuum-stmt +# -- syntax diagram vacuum-stmt # do_execsql_test e_vacuum-0.1 { VACUUM } {} diff --git a/test/eqp.test b/test/eqp.test index 454f2af..046088c 100644 --- a/test/eqp.test +++ b/test/eqp.test @@ -33,47 +33,47 @@ set testprefix eqp proc det {args} { uplevel do_eqp_test $args } do_execsql_test 1.1 { - CREATE TABLE t1(a, b); + CREATE TABLE t1(a INT, b INT, ex TEXT); CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t1(b); - CREATE TABLE t2(a, b); - CREATE TABLE t3(a, b); + CREATE TABLE t2(a INT, b INT, ex TEXT); + CREATE TABLE t3(a INT, b INT, ex TEXT); } do_eqp_test 1.2 { SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2; } { - 0 0 1 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)} - 0 0 1 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~10 rows)} - 0 1 0 {SCAN TABLE t2 (~1000000 rows)} + 0 0 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)} + 0 0 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)} + 0 1 0 {SCAN TABLE t2} } do_eqp_test 1.3 { SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2; } { - 0 0 0 {SCAN TABLE t2 (~1000000 rows)} - 0 1 1 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)} - 0 1 1 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~10 rows)} + 0 0 0 {SCAN TABLE t2} + 0 1 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)} + 0 1 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)} } do_eqp_test 1.3 { SELECT a FROM t1 ORDER BY a } { - 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} } do_eqp_test 1.4 { SELECT a FROM t1 ORDER BY +a } { - 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 1.5 { SELECT a FROM t1 WHERE a=4 } { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)} } do_eqp_test 1.6 { SELECT DISTINCT count(*) FROM t3 GROUP BY a; } { - 0 0 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 0 {SCAN TABLE t3} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } @@ -81,40 +81,40 @@ do_eqp_test 1.6 { do_eqp_test 1.7 { SELECT * FROM t3 JOIN (SELECT 1) } { - 0 0 1 {SCAN SUBQUERY 1 (~1 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.8 { SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2) } { 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)} - 0 0 1 {SCAN SUBQUERY 1 (~2 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.9 { SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) } { - 3 0 0 {SCAN TABLE t3 (~1000000 rows)} + 3 0 0 {SCAN TABLE t3} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (EXCEPT)} - 0 0 1 {SCAN SUBQUERY 1 (~17 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.10 { SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) } { - 3 0 0 {SCAN TABLE t3 (~1000000 rows)} + 3 0 0 {SCAN TABLE t3} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (INTERSECT)} - 0 0 1 {SCAN SUBQUERY 1 (~1 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.11 { SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) } { - 3 0 0 {SCAN TABLE t3 (~1000000 rows)} + 3 0 0 {SCAN TABLE t3} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION ALL)} - 0 0 1 {SCAN SUBQUERY 1 (~17 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } #------------------------------------------------------------------------- @@ -122,55 +122,55 @@ do_eqp_test 1.11 { # drop_all_tables do_execsql_test 2.1 { - CREATE TABLE t1(x, y); + CREATE TABLE t1(x INT, y INT, ex TEXT); - CREATE TABLE t2(x, y); + CREATE TABLE t2(x INT, y INT, ex TEXT); CREATE INDEX t2i1 ON t2(x); } det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 2.2.3 "SELECT DISTINCT * FROM t1" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } det 2.2.4 "SELECT DISTINCT * FROM t1, t2" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} - 0 1 1 {SCAN TABLE t2 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} - 0 1 1 {SCAN TABLE t2 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" { - 0 0 1 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} - 0 1 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 1 {SCAN TABLE t2 USING COVERING INDEX t2i1} + 0 1 0 {SCAN TABLE t1} } det 2.3.1 "SELECT max(x) FROM t2" { - 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1 (~1 rows)} + 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1} } det 2.3.2 "SELECT min(x) FROM t2" { - 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1 (~1 rows)} + 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1} } det 2.3.3 "SELECT min(x), max(x) FROM t2" { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} } det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" { - 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} } @@ -181,39 +181,39 @@ det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" { do_eqp_test 3.1.1 { SELECT (SELECT x FROM t1 AS sub) FROM t1; } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t1 AS sub (~1000000 rows)} + 1 0 0 {SCAN TABLE t1 AS sub} } do_eqp_test 3.1.2 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub); } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t1 AS sub (~1000000 rows)} + 1 0 0 {SCAN TABLE t1 AS sub} } do_eqp_test 3.1.3 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y); } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t1 AS sub (~1000000 rows)} + 1 0 0 {SCAN TABLE t1 AS sub} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 3.1.4 { SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x); } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} } det 3.2.1 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 0 0 0 {SCAN SUBQUERY 1 (~10 rows)} + 0 0 0 {SCAN SUBQUERY 1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 3.2.2 { @@ -222,34 +222,34 @@ det 3.2.2 { (SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2 ORDER BY x2.y LIMIT 5 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 USING INDEX t2i1 (~1000000 rows)} - 0 0 0 {SCAN SUBQUERY 1 AS x1 (~10 rows)} - 0 1 1 {SCAN SUBQUERY 2 AS x2 (~10 rows)} + 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} + 0 0 0 {SCAN SUBQUERY 1 AS x1} + 0 1 1 {SCAN SUBQUERY 2 AS x2} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 3.3.1 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2) } { - 0 0 0 {SCAN TABLE t1 (~100000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE LIST SUBQUERY 1} - 1 0 0 {SCAN TABLE t2 (~1000000 rows)} + 1 0 0 {SCAN TABLE t2} } det 3.3.2 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x) } { - 0 0 0 {SCAN TABLE t1 (~500000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1} - 1 0 0 {SCAN TABLE t2 (~500000 rows)} + 1 0 0 {SCAN TABLE t2} } det 3.3.3 { SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x) } { - 0 0 0 {SCAN TABLE t1 (~500000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t2 (~500000 rows)} + 1 0 0 {SCAN TABLE t2} } #------------------------------------------------------------------------- @@ -258,43 +258,43 @@ det 3.3.3 { do_eqp_test 4.1.1 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} + 2 0 0 {SCAN TABLE t2} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_eqp_test 4.1.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_eqp_test 4.1.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)} } do_eqp_test 4.1.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)} } do_eqp_test 4.1.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } @@ -302,64 +302,64 @@ do_eqp_test 4.1.5 { do_eqp_test 4.2.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 USING INDEX t2i1 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_eqp_test 4.2.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} - 2 0 0 {USE TEMP B-TREE FOR ORDER BY} + 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} + 2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)} } do_eqp_test 4.2.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} - 2 0 0 {USE TEMP B-TREE FOR ORDER BY} + 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} + 2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)} } do_eqp_test 4.2.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} - 2 0 0 {USE TEMP B-TREE FOR ORDER BY} + 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} + 2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } do_eqp_test 4.3.1 { SELECT x FROM t1 UNION SELECT x FROM t2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} - 2 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} + 2 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)} } do_eqp_test 4.3.2 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 } { - 2 0 0 {SCAN TABLE t1 (~1000000 rows)} - 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 2 0 0 {SCAN TABLE t1} + 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)} - 4 0 0 {SCAN TABLE t1 (~1000000 rows)} + 4 0 0 {SCAN TABLE t1} 0 0 0 {COMPOUND SUBQUERIES 1 AND 4 USING TEMP B-TREE (UNION)} } do_eqp_test 4.3.3 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1 } { - 2 0 0 {SCAN TABLE t1 (~1000000 rows)} + 2 0 0 {SCAN TABLE t1} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} - 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION)} - 4 0 0 {SCAN TABLE t1 (~1000000 rows)} + 4 0 0 {SCAN TABLE t1} 4 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 4 (UNION)} } @@ -370,128 +370,147 @@ do_eqp_test 4.3.3 { # drop_all_tables -# EVIDENCE-OF: R-64208-08323 sqlite> EXPLAIN QUERY PLAN SELECT a, b -# FROM t1 WHERE a=1; 0|0|0|SCAN TABLE t1 (~100000 rows) -do_execsql_test 5.1.0 { CREATE TABLE t1(a, b) } +# EVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b +# FROM t1 WHERE a=1; +# 0|0|0|SCAN TABLE t1 +# +do_execsql_test 5.1.0 { CREATE TABLE t1(a INT, b INT, ex TEXT) } det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" { - 0 0 0 {SCAN TABLE t1 (~100000 rows)} + 0 0 0 {SCAN TABLE t1} } -# EVIDENCE-OF: R-09022-44606 sqlite> CREATE INDEX i1 ON t1(a); +# EVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; -# 0|0|0|SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows) +# 0|0|0|SEARCH TABLE t1 USING INDEX i1 +# do_execsql_test 5.2.0 { CREATE INDEX i1 ON t1(a) } det 5.2.1 "SELECT a, b FROM t1 WHERE a=1" { - 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} } -# EVIDENCE-OF: R-62228-34103 sqlite> CREATE INDEX i2 ON t1(a, b); +# EVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; -# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows) +# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) +# do_execsql_test 5.3.0 { CREATE INDEX i2 ON t1(a, b) } det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} } -# EVIDENCE-OF: R-22253-05302 sqlite> EXPLAIN QUERY PLAN SELECT t1.*, -# t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2; 0|0|0|SEARCH TABLE t1 -# USING COVERING INDEX i2 (a=? AND b>?) (~3 rows) 0|1|1|SCAN TABLE t2 -# (~1000000 rows) -do_execsql_test 5.4.0 {CREATE TABLE t2(c, d)} -det 5.4.1 "SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2" { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) (~2 rows)} - 0 1 1 {SCAN TABLE t2 (~1000000 rows)} +# EVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN +# SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2; +# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) +# 0|1|1|SCAN TABLE t2 +# +do_execsql_test 5.4.0 {CREATE TABLE t2(c INT, d INT, ex TEXT)} +det 5.4.1 "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2" { + 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} + 0 1 1 {SCAN TABLE t2} } -# EVIDENCE-OF: R-21040-07025 sqlite> EXPLAIN QUERY PLAN SELECT t1.*, -# t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2; 0|0|1|SEARCH TABLE t1 -# USING COVERING INDEX i2 (a=? AND b>?) (~3 rows) 0|1|0|SCAN TABLE t2 -# (~1000000 rows) -det 5.5 "SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2" { - 0 0 1 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) (~2 rows)} - 0 1 0 {SCAN TABLE t2 (~1000000 rows)} +# EVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN +# SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2; +# 0|0|1|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) +# 0|1|0|SCAN TABLE t2 +# +det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" { + 0 0 1 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} + 0 1 0 {SCAN TABLE t2} } -# EVIDENCE-OF: R-39007-61103 sqlite> CREATE INDEX i3 ON t1(b); +# EVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b); # sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2; -# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows) -# 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) (~10 rows) +# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) +# 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) +# do_execsql_test 5.5.0 {CREATE INDEX i3 ON t1(b)} -det 5.6.1 "SELECT * FROM t1 WHERE a=1 OR b=2" { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows)} - 0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?) (~10 rows)} +det 5.6.1 "SELECT a, b FROM t1 WHERE a=1 OR b=2" { + 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} + 0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} } -# EVIDENCE-OF: R-33025-54904 sqlite> EXPLAIN QUERY PLAN SELECT c, d -# FROM t2 ORDER BY c; 0|0|0|SCAN TABLE t2 (~1000000 rows) 0|0|0|USE TEMP -# B-TREE FOR ORDER BY +# EVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN +# SELECT c, d FROM t2 ORDER BY c; +# 0|0|0|SCAN TABLE t2 +# 0|0|0|USE TEMP B-TREE FOR ORDER BY +# det 5.7 "SELECT c, d FROM t2 ORDER BY c" { - 0 0 0 {SCAN TABLE t2 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } -# EVIDENCE-OF: R-38854-22809 sqlite> CREATE INDEX i4 ON t2(c); +# EVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c); # sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c; -# 0|0|0|SCAN TABLE t2 USING INDEX i4 (~1000000 rows) +# 0|0|0|SCAN TABLE t2 USING INDEX i4 +# do_execsql_test 5.8.0 {CREATE INDEX i4 ON t2(c)} det 5.8.1 "SELECT c, d FROM t2 ORDER BY c" { - 0 0 0 {SCAN TABLE t2 USING INDEX i4 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING INDEX i4} } -# EVIDENCE-OF: R-29884-43993 sqlite> EXPLAIN QUERY PLAN SELECT +# EVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT # (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2; -# 0|0|0|SCAN TABLE t2 (~1000000 rows) 0|0|0|EXECUTE SCALAR SUBQUERY 1 -# 1|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows) -# 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2 2|0|0|SEARCH TABLE t1 USING -# INDEX i3 (b=?) (~10 rows) +# 0|0|0|SCAN TABLE t2 +# 0|0|0|EXECUTE SCALAR SUBQUERY 1 +# 1|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) +# 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2 +# 2|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) +# det 5.9 { SELECT (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2 } { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i4 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows)} + 1 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} - 2 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?) (~10 rows)} + 2 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} } -# EVIDENCE-OF: R-17911-16445 sqlite> EXPLAIN QUERY PLAN SELECT -# count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x; -# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows) 0|0|0|SCAN -# SUBQUERY 1 (~1000000 rows) 0|0|0|USE TEMP B-TREE FOR GROUP BY +# EVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN +# SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x; +# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 +# 0|0|0|SCAN SUBQUERY 1 +# 0|0|0|USE TEMP B-TREE FOR GROUP BY +# det 5.10 { SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x } { - 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows)} - 0 0 0 {SCAN SUBQUERY 1 (~100 rows)} + 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} + 0 0 0 {SCAN SUBQUERY 1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} } -# EVIDENCE-OF: R-18544-33103 sqlite> EXPLAIN QUERY PLAN SELECT * FROM -# (SELECT * FROM t2 WHERE c=1), t1; 0|0|0|SEARCH TABLE t2 USING INDEX i4 -# (c=?) (~10 rows) 0|1|1|SCAN TABLE t1 (~1000000 rows) -det 5.11 "SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1" { - 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?) (~10 rows)} - 0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows)} +# EVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN +# SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1; +# 0|0|0|SEARCH TABLE t2 USING INDEX i4 (c=?) +# 0|1|1|SCAN TABLE t1 +# +det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" { + 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)} + 0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2} } -# EVIDENCE-OF: R-40701-42164 sqlite> EXPLAIN QUERY PLAN SELECT a FROM -# t1 UNION SELECT c FROM t2; 1|0|0|SCAN TABLE t1 (~1000000 rows) -# 2|0|0|SCAN TABLE t2 (~1000000 rows) 0|0|0|COMPOUND SUBQUERIES 1 AND 2 -# USING TEMP B-TREE (UNION) -det 5.12 "SELECT a FROM t1 UNION SELECT c FROM t2" { - 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 2 0 0 {SCAN TABLE t2 USING COVERING INDEX i4 (~1000000 rows)} +# EVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN +# SELECT a FROM t1 UNION SELECT c FROM t2; +# 1|0|0|SCAN TABLE t1 +# 2|0|0|SCAN TABLE t2 +# 0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION) +# +det 5.12 "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2" { + 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} + 2 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)} } -# EVIDENCE-OF: R-61538-24748 sqlite> EXPLAIN QUERY PLAN SELECT a FROM -# t1 EXCEPT SELECT d FROM t2 ORDER BY 1; 1|0|0|SCAN TABLE t1 USING -# COVERING INDEX i2 (~1000000 rows) 2|0|0|SCAN TABLE t2 (~1000000 rows) -# 2|0|0|USE TEMP B-TREE FOR ORDER BY 0|0|0|COMPOUND SUBQUERIES 1 AND 2 -# (EXCEPT) +# EVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN +# SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1; +# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 +# 2|0|0|SCAN TABLE t2 2|0|0|USE TEMP B-TREE FOR ORDER BY +# 0|0|0|COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) +# det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" { - 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows)} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } @@ -529,10 +548,10 @@ proc do_peqp_test {tn sql res} { } do_peqp_test 6.1 { - SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1 + SELECT a, b FROM t1 EXCEPT SELECT d, 99 FROM t2 ORDER BY 1 } [string trimleft { -1 0 0 SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows) -2 0 0 SCAN TABLE t2 (~1000000 rows) +1 0 0 SCAN TABLE t1 USING COVERING INDEX i2 +2 0 0 SCAN TABLE t2 2 0 0 USE TEMP B-TREE FOR ORDER BY 0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) }] @@ -544,26 +563,26 @@ do_peqp_test 6.1 { drop_all_tables do_execsql_test 7.0 { - CREATE TABLE t1(a, b); - CREATE TABLE t2(a, b); + CREATE TABLE t1(a INT, b INT, ex CHAR(100)); + CREATE TABLE t2(a INT, b INT, ex CHAR(100)); CREATE INDEX i1 ON t2(a); } det 7.1 "SELECT count(*) FROM t1" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} } det 7.2 "SELECT count(*) FROM t2" { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1(~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1} } do_execsql_test 7.3 { - INSERT INTO t1 VALUES(1, 2); - INSERT INTO t1 VALUES(3, 4); + INSERT INTO t1(a,b) VALUES(1, 2); + INSERT INTO t1(a,b) VALUES(3, 4); - INSERT INTO t2 VALUES(1, 2); - INSERT INTO t2 VALUES(3, 4); - INSERT INTO t2 VALUES(5, 6); + INSERT INTO t2(a,b) VALUES(1, 2); + INSERT INTO t2(a,b) VALUES(3, 4); + INSERT INTO t2(a,b) VALUES(5, 6); ANALYZE; } @@ -572,12 +591,56 @@ db close sqlite3 db test.db det 7.4 "SELECT count(*) FROM t1" { - 0 0 0 {SCAN TABLE t1 (~2 rows)} + 0 0 0 {SCAN TABLE t1} } det 7.5 "SELECT count(*) FROM t2" { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1(~3 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1} +} + +#------------------------------------------------------------------------- +# The following tests - eqp-8.* - test that queries that use the OP_Count +# optimization return something sensible with EQP. +# +drop_all_tables + +do_execsql_test 8.0 { + CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID; + CREATE TABLE t2(a, b, c); +} + +det 8.1.1 "SELECT * FROM t2" { + 0 0 0 {SCAN TABLE t2} +} + +det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" { + 0 0 0 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } +det 8.1.3 "SELECT count(*) FROM t2" { + 0 0 0 {SCAN TABLE t2} +} + +det 8.2.1 "SELECT * FROM t1" { + 0 0 0 {SCAN TABLE t1} +} + +det 8.2.2 "SELECT * FROM t1 WHERE b=?" { + 0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=?)} +} + +det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" { + 0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?)} +} + +det 8.2.4 "SELECT count(*) FROM t1" { + 0 0 0 {SCAN TABLE t1} +} + + + + + + finish_test diff --git a/test/errmsg.test b/test/errmsg.test index 6b3f3b7..8df8a70 100644 --- a/test/errmsg.test +++ b/test/errmsg.test @@ -78,14 +78,14 @@ do_test 2.2 { error_messages "INSERT INTO t1 VALUES('ghi', 'def')" } [list {*}{ SQLITE_ERROR {SQL logic error or missing database} - SQLITE_CONSTRAINT {column b is not unique} + SQLITE_CONSTRAINT {UNIQUE constraint failed: t1.b} }] verify_ex_errcode 2.2b SQLITE_CONSTRAINT_UNIQUE do_test 2.3 { error_messages_v2 "INSERT INTO t1 VALUES('ghi', 'def')" } [list {*}{ - SQLITE_CONSTRAINT {column b is not unique} - SQLITE_CONSTRAINT {column b is not unique} + SQLITE_CONSTRAINT {UNIQUE constraint failed: t1.b} + SQLITE_CONSTRAINT {UNIQUE constraint failed: t1.b} }] verify_ex_errcode 2.3b SQLITE_CONSTRAINT_UNIQUE diff --git a/test/exclusive.test b/test/exclusive.test index ffde891..c000dfe 100644 --- a/test/exclusive.test +++ b/test/exclusive.test @@ -506,4 +506,3 @@ do_execsql_test exclusive-6.5 { } {exclusive} finish_test - diff --git a/test/exclusive2.test b/test/exclusive2.test index 54203e3..712363e 100644 --- a/test/exclusive2.test +++ b/test/exclusive2.test @@ -301,7 +301,6 @@ do_test exclusive2-3.3 { readPagerChangeCounter test.db } {4} do_test exclusive2-3.4 { -breakpoint execsql { INSERT INTO t1 VALUES(randstr(200, 200)); } diff --git a/test/extension01.test b/test/extension01.test new file mode 100644 index 0000000..97b7726 --- /dev/null +++ b/test/extension01.test @@ -0,0 +1,83 @@ +# 2014-06-16 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests for various small extensions. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix extension01 + +load_static_extension db fileio +do_test 1.0 { + forcedelete file1.txt + set out [open ./file1.txt wb] + puts -nonewline $out "This is a text file without a line ending" + close $out + db eval { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); + INSERT INTO t1 VALUES(1, readfile('./file1.txt')); + SELECT * FROM t1; + } +} {1 {This is a text file without a line ending}} +do_test 1.1 { + forcedelete file2.txt + db nullvalue nil + db eval { + DELETE FROM t1; + INSERT INTO t1 VALUES(2, readfile(NULL)),(3, readfile('file2.txt')); + SELECT a, b, typeof(b) FROM t1; + } +} {2 nil null 3 nil null} + +do_test 1.2 { + db eval { + SELECT writefile('./file2.txt', 'A second test line'); + } +} {18} +do_test 1.3 { + set in [open ./file2.txt rb] + set x [read $in] + close $in + list $x [file size file2.txt] +} {{A second test line} 18} + +do_test 1.4 { + db eval { + SELECT writefile('./file2.txt', NULL); + } +} {0} +do_test 1.5 { + file size ./file2.txt +} {0} + +do_test 1.6 { + if {$::tcl_platform(platform)=="unix"} { + file attributes ./file2.txt -permissions r--r--r-- + } else { + file attributes ./file2.txt -readonly 1 + } + db eval { + SELECT writefile('./file2.txt', 'Another test'); + } +} {nil} +do_test 1.7 { + if {$::tcl_platform(platform)=="unix"} { + file attributes ./file2.txt -permissions rw-r--r-- + } else { + file attributes ./file2.txt -readonly 0 + } + db eval { + SELECT writefile(NULL, 'Another test'); + } +} {nil} + +finish_test diff --git a/test/fallocate.test b/test/fallocate.test index 8a5fa32..f523c2c 100644 --- a/test/fallocate.test +++ b/test/fallocate.test @@ -143,4 +143,3 @@ if {!$skipwaltests} { finish_test - diff --git a/test/filefmt.test b/test/filefmt.test index bc1af18..2df1424 100644 --- a/test/filefmt.test +++ b/test/filefmt.test @@ -248,4 +248,3 @@ do_test filefmt-4.4 { db2 close finish_test - diff --git a/test/fkey1.test b/test/fkey1.test index e7c00d1..90a4c44 100644 --- a/test/fkey1.test +++ b/test/fkey1.test @@ -117,5 +117,8 @@ do_test fkey1-3.4 { {0 0 t5 d {} {SET DEFAULT} CASCADE NONE} \ {0 1 t5 e {} {SET DEFAULT} CASCADE NONE} \ ] +do_test fkey1-3.5 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 0 0} finish_test diff --git a/test/fkey2.test b/test/fkey2.test index 3e5b27c..4c8daa0 100644 --- a/test/fkey2.test +++ b/test/fkey2.test @@ -104,38 +104,38 @@ set FkeySimpleSchema { set FkeySimpleTests { - 1.1 "INSERT INTO t2 VALUES(1, 3)" {1 {foreign key constraint failed}} + 1.1 "INSERT INTO t2 VALUES(1, 3)" {1 {FOREIGN KEY constraint failed}} 1.2 "INSERT INTO t1 VALUES(1, 2)" {0 {}} 1.3 "INSERT INTO t2 VALUES(1, 3)" {0 {}} - 1.4 "INSERT INTO t2 VALUES(2, 4)" {1 {foreign key constraint failed}} + 1.4 "INSERT INTO t2 VALUES(2, 4)" {1 {FOREIGN KEY constraint failed}} 1.5 "INSERT INTO t2 VALUES(NULL, 4)" {0 {}} - 1.6 "UPDATE t2 SET c=2 WHERE d=4" {1 {foreign key constraint failed}} + 1.6 "UPDATE t2 SET c=2 WHERE d=4" {1 {FOREIGN KEY constraint failed}} 1.7 "UPDATE t2 SET c=1 WHERE d=4" {0 {}} 1.9 "UPDATE t2 SET c=1 WHERE d=4" {0 {}} 1.10 "UPDATE t2 SET c=NULL WHERE d=4" {0 {}} - 1.11 "DELETE FROM t1 WHERE a=1" {1 {foreign key constraint failed}} - 1.12 "UPDATE t1 SET a = 2" {1 {foreign key constraint failed}} + 1.11 "DELETE FROM t1 WHERE a=1" {1 {FOREIGN KEY constraint failed}} + 1.12 "UPDATE t1 SET a = 2" {1 {FOREIGN KEY constraint failed}} 1.13 "UPDATE t1 SET a = 1" {0 {}} - 2.1 "INSERT INTO t4 VALUES(1, 3)" {1 {foreign key constraint failed}} + 2.1 "INSERT INTO t4 VALUES(1, 3)" {1 {FOREIGN KEY constraint failed}} 2.2 "INSERT INTO t3 VALUES(1, 2)" {0 {}} 2.3 "INSERT INTO t4 VALUES(1, 3)" {0 {}} - 4.1 "INSERT INTO t8 VALUES(1, 3)" {1 {foreign key constraint failed}} + 4.1 "INSERT INTO t8 VALUES(1, 3)" {1 {FOREIGN KEY constraint failed}} 4.2 "INSERT INTO t7 VALUES(2, 1)" {0 {}} 4.3 "INSERT INTO t8 VALUES(1, 3)" {0 {}} - 4.4 "INSERT INTO t8 VALUES(2, 4)" {1 {foreign key constraint failed}} + 4.4 "INSERT INTO t8 VALUES(2, 4)" {1 {FOREIGN KEY constraint failed}} 4.5 "INSERT INTO t8 VALUES(NULL, 4)" {0 {}} - 4.6 "UPDATE t8 SET c=2 WHERE d=4" {1 {foreign key constraint failed}} + 4.6 "UPDATE t8 SET c=2 WHERE d=4" {1 {FOREIGN KEY constraint failed}} 4.7 "UPDATE t8 SET c=1 WHERE d=4" {0 {}} 4.9 "UPDATE t8 SET c=1 WHERE d=4" {0 {}} 4.10 "UPDATE t8 SET c=NULL WHERE d=4" {0 {}} - 4.11 "DELETE FROM t7 WHERE b=1" {1 {foreign key constraint failed}} - 4.12 "UPDATE t7 SET b = 2" {1 {foreign key constraint failed}} + 4.11 "DELETE FROM t7 WHERE b=1" {1 {FOREIGN KEY constraint failed}} + 4.12 "UPDATE t7 SET b = 2" {1 {FOREIGN KEY constraint failed}} 4.13 "UPDATE t7 SET b = 1" {0 {}} - 4.14 "INSERT INTO t8 VALUES('a', 'b')" {1 {foreign key constraint failed}} - 4.15 "UPDATE t7 SET b = 5" {1 {foreign key constraint failed}} - 4.16 "UPDATE t7 SET rowid = 5" {1 {foreign key constraint failed}} + 4.14 "INSERT INTO t8 VALUES('a', 'b')" {1 {FOREIGN KEY constraint failed}} + 4.15 "UPDATE t7 SET b = 5" {1 {FOREIGN KEY constraint failed}} + 4.16 "UPDATE t7 SET rowid = 5" {1 {FOREIGN KEY constraint failed}} 4.17 "UPDATE t7 SET a = 10" {0 {}} 5.1 "INSERT INTO t9 VALUES(1, 3)" {1 {no such table: main.nosuchtable}} @@ -215,7 +215,7 @@ do_test fkey2-1.5.1 { } {35.0 text} do_test fkey2-1.5.2 { catchsql { DELETE FROM i } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} # Same test using a regular primary key with integer affinity. drop_all_tables @@ -231,7 +231,7 @@ do_test fkey2-1.6.1 { } {35.0 text 35 integer} do_test fkey2-1.6.2 { catchsql { DELETE FROM i } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} # Use a collation sequence on the parent key. drop_all_tables @@ -243,7 +243,7 @@ do_test fkey2-1.7.1 { INSERT INTO j VALUES('sqlite'); } catchsql { DELETE FROM i } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} # Use the parent key collation even if it is default and the child key # has an explicit value. @@ -255,7 +255,7 @@ do_test fkey2-1.7.2 { INSERT INTO i VALUES('SQLite'); } catchsql { INSERT INTO j VALUES('sqlite') } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-1.7.3 { execsql { INSERT INTO i VALUES('sqlite'); @@ -263,7 +263,7 @@ do_test fkey2-1.7.3 { DELETE FROM i WHERE i = 'SQLite'; } catchsql { DELETE FROM i WHERE i = 'sqlite' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} #------------------------------------------------------------------------- # This section (test cases fkey2-2.*) contains tests to check that the @@ -271,7 +271,7 @@ do_test fkey2-1.7.3 { # proc fkey2-2-test {tn nocommit sql {res {}}} { if {$res eq "FKV"} { - set expected {1 {foreign key constraint failed}} + set expected {1 {FOREIGN KEY constraint failed}} } else { set expected [list 0 $res] } @@ -279,7 +279,7 @@ proc fkey2-2-test {tn nocommit sql {res {}}} { if {$nocommit} { do_test fkey2-2.${tn}c { catchsql COMMIT - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} } } @@ -375,7 +375,7 @@ fkey2-2-test 65 1 "INSERT INTO leaf VALUES('b', 2)" fkey2-2-test 66 1 "INSERT INTO leaf VALUES('c', 1)" do_test fkey2-2-test-67 { catchsql "INSERT INTO node SELECT parent, 3 FROM leaf" -} {1 {column nodeid is not unique}} +} {1 {UNIQUE constraint failed: node.nodeid}} fkey2-2-test 68 0 "COMMIT" FKV fkey2-2-test 69 1 "INSERT INTO node VALUES(1, NULL)" fkey2-2-test 70 0 "INSERT INTO node VALUES(2, NULL)" @@ -417,14 +417,14 @@ do_test fkey2-3.1.2 { } {} do_test fkey2-3.1.3 { catchsql { UPDATE ab SET a = 5 } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: ef}} do_test fkey2-3.1.4 { execsql { SELECT * FROM ab } } {1 b} do_test fkey2-3.1.4 { execsql BEGIN; catchsql { UPDATE ab SET a = 5 } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: ef}} do_test fkey2-3.1.5 { execsql COMMIT; execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef } @@ -433,7 +433,7 @@ do_test fkey2-3.1.5 { do_test fkey2-3.2.1 { execsql BEGIN; catchsql { DELETE FROM ab } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-3.2.2 { execsql COMMIT execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef } @@ -555,7 +555,7 @@ do_test fkey2-7.1 { } {} do_test fkey2-7.2 { catchsql { INSERT INTO t2 VALUES(1, 'A'); } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-7.3 { execsql { INSERT INTO t1 VALUES(1, 2); @@ -568,19 +568,19 @@ do_test fkey2-7.4 { } {} do_test fkey2-7.5 { catchsql { UPDATE t2 SET c = 3 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-7.6 { catchsql { DELETE FROM t1 WHERE a = 2 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-7.7 { execsql { DELETE FROM t1 WHERE a = 1 } } {} do_test fkey2-7.8 { catchsql { UPDATE t1 SET a = 3 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-7.9 { catchsql { UPDATE t2 SET rowid = 3 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} #------------------------------------------------------------------------- # Test that it is not possible to enable/disable FK support while a @@ -645,7 +645,7 @@ do_test fkey2-9.1.4 { } {2 two} do_test fkey2-9.1.5 { catchsql { DELETE FROM t1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-9.2.1 { execsql { @@ -780,13 +780,13 @@ do_test fkey2-12.1.3 { } {} do_test fkey2-12.1.4 { catchsql "UPDATE t1 SET b = 'five' WHERE b = 'two'" -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-12.1.5 { execsql "DELETE FROM t1 WHERE b = 'two'" } {} do_test fkey2-12.1.6 { catchsql "COMMIT" -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-12.1.7 { execsql { INSERT INTO t1 VALUES(2, 'two'); @@ -828,7 +828,7 @@ do_test fkey2-12.2.3 { INSERT INTO t2 VALUES('b'); } catchsql { DELETE FROM t1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-12.2.4 { execsql { SELECT * FROM t1; @@ -866,14 +866,14 @@ do_test fkey2-12.3.2 { } {no possibly} do_test fkey2-12.3.3 { catchsql { INSERT INTO down(c39, c38) VALUES('yes', 'no') } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-12.3.4 { execsql { INSERT INTO up(c34, c35) VALUES('yes', 'no'); INSERT INTO down(c39, c38) VALUES('yes', 'no'); } catchsql { DELETE FROM up WHERE c34 = 'yes' } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-12.3.5 { execsql { DELETE FROM up WHERE c34 = 'possibly'; @@ -901,7 +901,7 @@ foreach {tn stmt} { } { do_test fkey2-13.1.$tn.1 { catchsql $stmt - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-13.1.$tn.2 { execsql { SELECT * FROM pp; @@ -911,7 +911,7 @@ foreach {tn stmt} { do_test fkey2-13.1.$tn.3 { execsql BEGIN; catchsql $stmt - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-13.1.$tn.4 { execsql { COMMIT; @@ -1015,13 +1015,13 @@ ifcapable altertable { ] do_test fkey2-14.2.2.3 { catchsql { INSERT INTO t3 VALUES(1, 2, 3) } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-14.2.2.4 { execsql { INSERT INTO t4 VALUES(1, NULL) } } {} do_test fkey2-14.2.2.5 { catchsql { UPDATE t4 SET b = 5 } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-14.2.2.6 { catchsql { UPDATE t4 SET b = 1 } } {0 {}} @@ -1096,13 +1096,13 @@ ifcapable altertable { ] do_test fkey2-14.2tmp.2.3 { catchsql { INSERT INTO t3 VALUES(1, 2, 3) } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-14.2tmp.2.4 { execsql { INSERT INTO t4 VALUES(1, NULL) } } {} do_test fkey2-14.2tmp.2.5 { catchsql { UPDATE t4 SET b = 5 } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-14.2tmp.2.6 { catchsql { UPDATE t4 SET b = 1 } } {0 {}} @@ -1178,13 +1178,13 @@ ifcapable altertable { ] do_test fkey2-14.2aux.2.3 { catchsql { INSERT INTO t3 VALUES(1, 2, 3) } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-14.2aux.2.4 { execsql { INSERT INTO t4 VALUES(1, NULL) } } {} do_test fkey2-14.2aux.2.5 { catchsql { UPDATE t4 SET b = 5 } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-14.2aux.2.6 { catchsql { UPDATE t4 SET b = 1 } } {0 {}} @@ -1210,7 +1210,7 @@ do_test fkey-2.14.3.2 { } {} do_test fkey-2.14.3.3 { catchsql { DROP TABLE t1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey-2.14.3.4 { execsql { DELETE FROM t2; @@ -1229,7 +1229,7 @@ do_test fkey-2.14.3.5 { } {} do_test fkey-2.14.3.6 { catchsql { DROP TABLE t1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey-2.14.3.7 { execsql { DROP TABLE t2; @@ -1387,15 +1387,15 @@ foreach {tn zSchema} { do_test fkey2-16.1.$tn.3 { catchsql { UPDATE self SET b = 15 } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-16.1.$tn.4 { catchsql { UPDATE self SET a = 15 } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-16.1.$tn.5 { catchsql { UPDATE self SET a = 15, b = 16 } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-16.1.$tn.6 { catchsql { UPDATE self SET a = 17, b = 17 } @@ -1406,7 +1406,7 @@ foreach {tn zSchema} { } {} do_test fkey2-16.1.$tn.8 { catchsql { INSERT INTO self VALUES(20, 21) } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} } #------------------------------------------------------------------------- @@ -1463,7 +1463,7 @@ do_test fkey2-17.1.6 { INSERT INTO one VALUES(0, 0, 0); UPDATE two SET e=e+1, f=f+1; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-17.1.7 { execsql { SELECT * FROM one } } {1 2 3 2 3 4 3 4 5 0 0 0} @@ -1619,7 +1619,7 @@ ifcapable auth { } do_test fkey2-18.8 { catchsql { INSERT INTO short VALUES(1, 3, 2) } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-18.9 { execsql { INSERT INTO short VALUES(1, 3, NULL) } } {} @@ -1628,7 +1628,7 @@ ifcapable auth { } {1 3 2 1 3 {}} do_test fkey2-18.11 { catchsql { UPDATE short SET f = 2 WHERE f IS NULL } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} db auth {} unset authargs @@ -1680,7 +1680,7 @@ foreach {tn insert} { } { do_test fkey2-20.2.$tn.1 { catchsql "$insert INTO cc VALUES(1, 2)" - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-20.2.$tn.2 { execsql { SELECT * FROM cc } } {} @@ -1691,7 +1691,7 @@ foreach {tn insert} { INSERT INTO cc VALUES(1, 2); } catchsql "$insert INTO cc VALUES(3, 4)" - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-20.2.$tn.4 { execsql { COMMIT ; SELECT * FROM cc } } {1 2} @@ -1716,13 +1716,13 @@ foreach {tn update} { } {} do_test fkey2-20.3.$tn.2 { catchsql "$update pp SET a = 1" - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-20.3.$tn.3 { execsql { SELECT * FROM pp } } {2 two} do_test fkey2-20.3.$tn.4 { catchsql "$update cc SET d = 1" - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-20.3.$tn.5 { execsql { SELECT * FROM cc } } {1 2} @@ -1732,7 +1732,7 @@ foreach {tn update} { INSERT INTO pp VALUES(3, 'three'); } catchsql "$update pp SET a = 1 WHERE a = 2" - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-20.3.$tn.7 { execsql { COMMIT ; SELECT * FROM pp } } {2 two 3 three} @@ -1742,7 +1742,7 @@ foreach {tn update} { INSERT INTO cc VALUES(2, 2); } catchsql "$update cc SET d = 1 WHERE c = 1" - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test fkey2-20.3.$tn.9 { execsql { COMMIT ; SELECT * FROM cc } } {1 2 2 2} @@ -1768,7 +1768,7 @@ do_test fkey2-genfkey.1.1 { } {} do_test fkey2-genfkey.1.2 { catchsql { INSERT INTO t2 VALUES(1, 2) } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-genfkey.1.3 { execsql { INSERT INTO t1 VALUES(1, 2, 3); @@ -1780,7 +1780,7 @@ do_test fkey2-genfkey.1.4 { } {} do_test fkey2-genfkey.1.5 { catchsql { UPDATE t2 SET e = 5 WHERE e IS NULL } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-genfkey.1.6 { execsql { UPDATE t2 SET e = 1 WHERE e IS NULL } } {} @@ -1789,13 +1789,13 @@ do_test fkey2-genfkey.1.7 { } {} do_test fkey2-genfkey.1.8 { catchsql { UPDATE t1 SET a = 10 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-genfkey.1.9 { catchsql { UPDATE t1 SET a = NULL } } {1 {datatype mismatch}} do_test fkey2-genfkey.1.10 { catchsql { DELETE FROM t1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-genfkey.1.11 { execsql { UPDATE t2 SET e = NULL } } {} @@ -1815,7 +1815,7 @@ do_test fkey2-genfkey.1.13 { } {} do_test fkey2-genfkey.1.14 { catchsql { INSERT INTO t3 VALUES(3, 1, 4) } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-genfkey.1.15 { execsql { INSERT INTO t1 VALUES(1, 1, 4); @@ -1824,16 +1824,16 @@ do_test fkey2-genfkey.1.15 { } {} do_test fkey2-genfkey.1.16 { catchsql { DELETE FROM t1 } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-genfkey.1.17 { catchsql { UPDATE t1 SET b = 10} -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-genfkey.1.18 { execsql { UPDATE t1 SET a = 10} } {} do_test fkey2-genfkey.1.19 { catchsql { UPDATE t3 SET h = 'hello' WHERE i = 3} -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} drop_all_tables do_test fkey2-genfkey.2.1 { @@ -1946,7 +1946,7 @@ do_test fkey2-dd08e5.1.2 { catchsql { DELETE FROM tdd08; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-dd08e5.1.3 { execsql { SELECT * FROM tdd08; @@ -1956,17 +1956,17 @@ do_test fkey2-dd08e5.1.4 { catchsql { INSERT INTO tdd08_b VALUES(400,500,300); } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-dd08e5.1.5 { catchsql { UPDATE tdd08_b SET x=x+1; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-dd08e5.1.6 { catchsql { UPDATE tdd08 SET a=a+1; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} #------------------------------------------------------------------------- # Verify that ticket ce7c133ea6cc9ccdc1a60d80441f80b6180f5eba @@ -1987,12 +1987,12 @@ do_test fkey2-ce7c13.1.2 { catchsql { UPDATE tce71 set b = 201 where a = 100; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-ce7c13.1.3 { catchsql { UPDATE tce71 set a = 101 where a = 100; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-ce7c13.1.4 { execsql { CREATE TABLE tce73(a INTEGER PRIMARY KEY, b, UNIQUE(a,b)); @@ -2007,11 +2007,11 @@ do_test fkey2-ce7c13.1.5 { catchsql { UPDATE tce73 set b = 201 where a = 100; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey2-ce7c13.1.6 { catchsql { UPDATE tce73 set a = 101 where a = 100; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} finish_test diff --git a/test/fkey3.test b/test/fkey3.test index 6a11f88..a8d0382 100644 --- a/test/fkey3.test +++ b/test/fkey3.test @@ -43,13 +43,13 @@ do_test fkey3-1.2 { catchsql { DELETE FROM t1 WHERE x=100; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey3-1.3 { catchsql { DROP TABLE t1; } -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_test fkey3-1.4 { execsql { @@ -95,17 +95,17 @@ do_execsql_test 3.1.1 { } {} do_catchsql_test 3.1.2 { INSERT INTO t3 VALUES(NULL, 2, 5, 2); -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_catchsql_test 3.1.3 { INSERT INTO t3 VALUES(NULL, 3, 5, 2); -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_execsql_test 3.2.1 { CREATE TABLE t4(a UNIQUE, b REFERENCES t4(a)); } do_catchsql_test 3.2.2 { INSERT INTO t4 VALUES(NULL, 1); -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_execsql_test 3.3.1 { CREATE TABLE t5(a INTEGER PRIMARY KEY, b REFERENCES t5(a)); @@ -113,7 +113,7 @@ do_execsql_test 3.3.1 { } {} do_catchsql_test 3.3.2 { INSERT INTO t5 VALUES(NULL, 3); -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_execsql_test 3.4.1 { CREATE TABLE t6(a INTEGER PRIMARY KEY, b, c, d, @@ -127,7 +127,7 @@ do_execsql_test 3.4.4 { INSERT INTO t6 VALUES(NULL, 'a', 1, 'a'); } {} do_execsql_test 3.4.5 { INSERT INTO t6 VALUES(5, 'a', 2, 'a'); } {} do_catchsql_test 3.4.6 { INSERT INTO t6 VALUES(NULL, 'a', 65, 'a'); -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_execsql_test 3.4.7 { INSERT INTO t6 VALUES(100, 'one', 100, 'one'); @@ -149,10 +149,10 @@ do_execsql_test 3.5.2 { INSERT INTO t7 VALUES('x', 1, 'x', NULL) } {} do_execsql_test 3.5.3 { INSERT INTO t7 VALUES('x', 2, 'x', 2) } {} do_catchsql_test 3.5.4 { INSERT INTO t7 VALUES('x', 450, 'x', NULL); -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_catchsql_test 3.5.5 { INSERT INTO t7 VALUES('x', 450, 'x', 451); -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_execsql_test 3.6.1 { @@ -163,7 +163,7 @@ do_execsql_test 3.6.1 { } do_catchsql_test 3.6.2 { UPDATE t8 SET d = 2; -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_execsql_test 3.6.3 { UPDATE t8 SET d = 1; } do_execsql_test 3.6.4 { UPDATE t8 SET e = 2; } @@ -181,6 +181,6 @@ do_catchsql_test 3.6.5 { INSERT INTO TestTable VALUES (1, 'parent', 1, null); INSERT INTO TestTable VALUES (2, 'child', 1, 1); UPDATE TestTable SET parent_id=1000 where id=2; -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} finish_test diff --git a/test/fkey5.test b/test/fkey5.test index 40a1a5e..5aa8b1d 100644 --- a/test/fkey5.test +++ b/test/fkey5.test @@ -12,9 +12,12 @@ # # This file tests the PRAGMA foreign_key_check command. # +# EVIDENCE-OF: R-05426-18119 PRAGMA foreign_key_check; PRAGMA +# foreign_key_check(table-name); set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix fkey5 ifcapable {!foreignkey} { finish_test @@ -82,6 +85,20 @@ do_test fkey5-1.4 { } } {} +# EVIDENCE-OF: R-45728-08709 There are four columns in each result row. +# +# EVIDENCE-OF: R-55672-01620 The first column is the name of the table +# that contains the REFERENCES clause. +# +# EVIDENCE-OF: R-25219-25618 The second column is the rowid of the row +# that contains the invalid REFERENCES clause. +# +# EVIDENCE-OF: R-40482-20265 The third column is the name of the table +# that is referred to. +# +# EVIDENCE-OF: R-62839-07969 The fourth column is the index of the +# specific foreign key constraint that failed. +# do_test fkey5-2.0 { db eval { INSERT INTO c5 SELECT x FROM c1; @@ -99,6 +116,9 @@ do_test fkey5-2.2 { PRAGMA foreign_key_check(c1); } } {} +do_execsql_test fkey5-2.3 { + PRAGMA foreign_key_list(c5); +} {0 0 p1 x {} {NO ACTION} {NO ACTION} NONE} do_test fkey5-3.0 { db eval { @@ -306,5 +326,38 @@ do_test fkey5-8.7 { } {} +#------------------------------------------------------------------------- +# Tests 9.* verify that missing parent tables are handled correctly. +# +do_execsql_test 9.1.1 { + CREATE TABLE k1(x REFERENCES s1); + PRAGMA foreign_key_check(k1); +} {} +do_execsql_test 9.1.2 { + INSERT INTO k1 VALUES(NULL); + PRAGMA foreign_key_check(k1); +} {} +do_execsql_test 9.1.3 { + INSERT INTO k1 VALUES(1); + PRAGMA foreign_key_check(k1); +} {k1 2 s1 0} + +do_execsql_test 9.2.1 { + CREATE TABLE k2(x, y, FOREIGN KEY(x, y) REFERENCES s1(a, b)); + PRAGMA foreign_key_check(k2); +} {} +do_execsql_test 9.2 { + INSERT INTO k2 VALUES(NULL, 'five'); + PRAGMA foreign_key_check(k2); +} {} +do_execsql_test 9.3 { + INSERT INTO k2 VALUES('one', NULL); + PRAGMA foreign_key_check(k2); +} {} +do_execsql_test 9.4 { + INSERT INTO k2 VALUES('six', 'seven'); + PRAGMA foreign_key_check(k2); +} {k2 3 s1 0} + finish_test diff --git a/test/fkey6.test b/test/fkey6.test new file mode 100644 index 0000000..6fc3de2 --- /dev/null +++ b/test/fkey6.test @@ -0,0 +1,175 @@ +# 2013-07-11 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file tests the PRAGMA defer_foreign_keys and +# SQLITE_DBSTATUS_DEFERRED_FKS +# +# EVIDENCE-OF: R-18981-16292 When the defer_foreign_keys PRAGMA is on, +# enforcement of all foreign key constraints is delayed until the +# outermost transaction is committed. +# +# EVIDENCE-OF: R-28911-57501 The defer_foreign_keys pragma defaults to +# OFF so that foreign key constraints are only deferred if they are +# created as "DEFERRABLE INITIALLY DEFERRED". + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable {!foreignkey} { + finish_test + return +} + +do_execsql_test fkey6-1.0 { + PRAGMA defer_foreign_keys; +} {0} + +do_execsql_test fkey6-1.1 { + PRAGMA foreign_keys=ON; + CREATE TABLE t1(x INTEGER PRIMARY KEY); + CREATE TABLE t2(y INTEGER PRIMARY KEY, + z INTEGER REFERENCES t1(x) DEFERRABLE INITIALLY DEFERRED); + CREATE INDEX t2z ON t2(z); + CREATE TABLE t3(u INTEGER PRIMARY KEY, v INTEGER REFERENCES t1(x)); + CREATE INDEX t3v ON t3(v); + INSERT INTO t1 VALUES(1),(2),(3),(4),(5); + INSERT INTO t2 VALUES(1,1),(2,2); + INSERT INTO t3 VALUES(3,3),(4,4); +} {} +do_test fkey6-1.2 { + catchsql {DELETE FROM t1 WHERE x=2;} +} {1 {FOREIGN KEY constraint failed}} +do_test fkey6-1.3 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 0 0} +do_test fkey6-1.4 { + execsql { + BEGIN; + DELETE FROM t1 WHERE x=1; + } +} {} +do_test fkey6-1.5.1 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 1 +} {0 1 0} +do_test fkey6-1.5.2 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 1 0} +do_test fkey6-1.6 { + execsql { + ROLLBACK; + } +} {} +do_test fkey6-1.7 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 0 0} +do_test fkey6-1.8 { + execsql { + PRAGMA defer_foreign_keys=ON; + BEGIN; + DELETE FROM t1 WHERE x=3; + } +} {} +do_test fkey6-1.9 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 1 0} + +# EVIDENCE-OF: R-21752-26913 The defer_foreign_keys pragma is +# automatically switched off at each COMMIT or ROLLBACK. Hence, the +# defer_foreign_keys pragma must be separately enabled for each +# transaction. +do_execsql_test fkey6-1.10.1 { + PRAGMA defer_foreign_keys; + ROLLBACK; + PRAGMA defer_foreign_keys; + BEGIN; + PRAGMA defer_foreign_keys=ON; + PRAGMA defer_foreign_keys; + COMMIT; + PRAGMA defer_foreign_keys; + BEGIN; +} {1 0 1 0} +do_test fkey6-1.10.2 { + catchsql {DELETE FROM t1 WHERE x=3} +} {1 {FOREIGN KEY constraint failed}} +db eval {ROLLBACK} + +do_test fkey6-1.20 { + execsql { + BEGIN; + DELETE FROM t1 WHERE x=1; + } + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 1 0} +do_test fkey6-1.21 { + execsql { + DELETE FROM t2 WHERE y=1; + } + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 0 0} +do_test fkey6-1.22 { + execsql { + COMMIT; + } +} {} + +do_execsql_test fkey6-2.1 { + CREATE TABLE p1(a PRIMARY KEY); + INSERT INTO p1 VALUES('one'), ('two'); + CREATE TABLE c1(x REFERENCES p1); + INSERT INTO c1 VALUES('two'), ('one'); +} + +do_execsql_test fkey6-2.2 { + BEGIN; + PRAGMA defer_foreign_keys = 1; + DELETE FROM p1; + ROLLBACK; + PRAGMA defer_foreign_keys; +} {0} + +do_execsql_test fkey6-2.3 { + BEGIN; + PRAGMA defer_foreign_keys = 1; + DROP TABLE p1; + PRAGMA vdbe_trace = 0; + ROLLBACK; + PRAGMA defer_foreign_keys; +} {0} + +do_execsql_test fkey6-2.4 { + BEGIN; + PRAGMA defer_foreign_keys = 1; + DELETE FROM p1; + DROP TABLE c1; + COMMIT; + PRAGMA defer_foreign_keys; +} {0} + +do_execsql_test fkey6-2.5 { + DROP TABLE p1; + CREATE TABLE p1(a PRIMARY KEY); + INSERT INTO p1 VALUES('one'), ('two'); + CREATE TABLE c1(x REFERENCES p1); + INSERT INTO c1 VALUES('two'), ('one'); +} + +do_execsql_test fkey6-2.6 { + BEGIN; + PRAGMA defer_foreign_keys = 1; + INSERT INTO c1 VALUES('three'); + DROP TABLE c1; + COMMIT; + PRAGMA defer_foreign_keys; +} {0} + + +finish_test diff --git a/test/fkey7.test b/test/fkey7.test new file mode 100644 index 0000000..c2682ed --- /dev/null +++ b/test/fkey7.test @@ -0,0 +1,54 @@ +# 2001 September 15 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests for foreign keys. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fkey7 + +ifcapable {!foreignkey} { + finish_test + return +} + +do_execsql_test 1.1 { + PRAGMA foreign_keys = 1; + + CREATE TABLE s1(a PRIMARY KEY, b); + CREATE TABLE par(a, b REFERENCES s1, c UNIQUE, PRIMARY KEY(a)); + + CREATE TABLE c1(a, b REFERENCES par); + CREATE TABLE c2(a, b REFERENCES par); + CREATE TABLE c3(a, b REFERENCES par(c)); +} + +proc auth {op tbl args} { + if {$op == "SQLITE_READ"} { set ::tbls($tbl) 1 } + return "SQLITE_OK" +} +db auth auth +db cache size 0 +proc do_tblsread_test {tn sql tbllist} { + array unset ::tbls + uplevel [list execsql $sql] + uplevel [list do_test $tn {lsort [array names ::tbls]} $tbllist] +} + +do_tblsread_test 1.2 { UPDATE par SET b=? WHERE a=? } {par s1} +do_tblsread_test 1.3 { UPDATE par SET a=? WHERE b=? } {c1 c2 par} +do_tblsread_test 1.4 { UPDATE par SET c=? WHERE b=? } {c3 par} +do_tblsread_test 1.5 { UPDATE par SET a=?,b=?,c=? WHERE b=? } {c1 c2 c3 par s1} + + +finish_test diff --git a/test/fkey_malloc.test b/test/fkey_malloc.test index b4b5b4e..382e6f6 100644 --- a/test/fkey_malloc.test +++ b/test/fkey_malloc.test @@ -69,7 +69,10 @@ proc catch_fk_error {zSql} { if {[string match {*foreign key*} $msg]} { return "" } - if {$msg eq "out of memory" || $msg eq "constraint failed"} { + if {$msg eq "out of memory" + || $msg eq "FOREIGN KEY constraint failed" + || $msg eq "constraint failed" + } { error 1 } error $msg diff --git a/test/fts3aa.test b/test/fts3aa.test index 5d79e93..6ff384a 100644 --- a/test/fts3aa.test +++ b/test/fts3aa.test @@ -146,7 +146,6 @@ do_test fts3aa-3.3 { execsql {SELECT rowid FROM t1 WHERE content MATCH '-two one'} } {1 5 9 13 17 21 25 29} -breakpoint do_test fts3aa-4.1 { execsql {SELECT rowid FROM t1 WHERE content MATCH 'one OR two'} } {1 2 3 5 6 7 9 10 11 13 14 15 17 18 19 21 22 23 25 26 27 29 30 31} @@ -224,4 +223,3 @@ do_catchsql_test fts3aa-7.5 { finish_test - diff --git a/test/fts3ab.test b/test/fts3ab.test index e1f3bdc..86124f7 100644 --- a/test/fts3ab.test +++ b/test/fts3ab.test @@ -115,7 +115,6 @@ for {set i 1} {$i<=15} {incr i} { db eval "INSERT INTO t4(norm,plusone,invert) VALUES([join $vset ,]);" } -breakpoint do_test fts3ab-4.1 { execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'norm:one'} } {1 3 5 7 9 11 13 15} diff --git a/test/fts3ag.test b/test/fts3ag.test index 18ed5ae..9b658d1 100644 --- a/test/fts3ag.test +++ b/test/fts3ag.test @@ -78,7 +78,6 @@ do_test fts3ag-1.10 { # Test that docListOrMerge() correctly handles reaching the end of one # doclist before it reaches the end of the other. do_test fts3ag-1.11 { -breakpoint execsql {SELECT rowid FROM t1 WHERE t1 MATCH 'this OR also'} } {1 2} do_test fts3ag-1.12 { diff --git a/test/fts3ao.test b/test/fts3ao.test index 786667a..60f0aa7 100644 --- a/test/fts3ao.test +++ b/test/fts3ao.test @@ -219,5 +219,32 @@ do_execsql_test 5.2 { SELECT count(*) FROM sqlite_master WHERE name LIKE 't8%'; } {0 6} -finish_test +# At one point this was causing a memory leak. +# +foreach {tn sql} { + 1 {} + 2 { INSERT INTO ft(ft) VALUES('merge=2,2'); } +} { + reset_db + do_execsql_test 6.$tn.1 " + CREATE TABLE t1(x); + CREATE VIRTUAL TABLE ft USING fts3; + INSERT INTO ft VALUES('hello world'); + $sql + " + + db close + sqlite3 db test.db + do_execsql_test 6.$tn.2 { SELECT * FROM t1 } {} + + do_test 6.$tn.3 { + sqlite3 db2 test.db + db2 eval { DROP TABLE t1 } + db2 close + set stmt [sqlite3_prepare db { SELECT * FROM ft } -1 dummy] + sqlite3_finalize $stmt + } {SQLITE_OK} + db close +} +finish_test diff --git a/test/fts3atoken.test b/test/fts3atoken.test index 9277bfb..b7722c7 100644 --- a/test/fts3atoken.test +++ b/test/fts3atoken.test @@ -193,5 +193,3 @@ do_test fts3token-internal { finish_test - - diff --git a/test/fts3auto.test b/test/fts3auto.test index 20b2812..20640d2 100644 --- a/test/fts3auto.test +++ b/test/fts3auto.test @@ -707,4 +707,3 @@ foreach {tn create} { set sqlite_fts3_enable_parentheses $sfep finish_test - diff --git a/test/fts3aux1.test b/test/fts3aux1.test index ef17949..d17ac85 100644 --- a/test/fts3aux1.test +++ b/test/fts3aux1.test @@ -105,10 +105,10 @@ db func rec rec # do_execsql_test 2.1.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} } do_execsql_test 2.1.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid' -} {0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)}} +} {0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}} # Now show that using "term='braid'" means the virtual table returns # only 1 row to SQLite, but "+term='braid'" means all 19 are returned. @@ -154,24 +154,24 @@ do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {} do_execsql_test 2.2.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 2: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 2:} } do_execsql_test 2.2.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} } do_execsql_test 2.2.1.3 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 4: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 4:} } do_execsql_test 2.2.1.4 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} } do_execsql_test 2.2.1.5 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term BETWEEN 'brags' AND 'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 6: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 6:} } do_execsql_test 2.2.1.6 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term BETWEEN 'brags' AND 'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} } do_test 2.2.2.1 { set cnt 0 @@ -335,7 +335,7 @@ foreach {tn sort orderby} { 9 1 "ORDER BY occurrences DESC" } { - set res [list 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)}] + set res [list 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}] if {$sort} { lappend res 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } set sql "SELECT * FROM terms $orderby" @@ -410,32 +410,32 @@ proc do_plansql_test {tn sql r} { do_plansql_test 4.2 { SELECT y FROM x2, terms WHERE y = term AND col = '*' } { - 0 0 0 {SCAN TABLE x2 (~1000000 rows)} - 0 1 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~0 rows)} + 0 0 0 {SCAN TABLE x2} + 0 1 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} a b c d e f g h i j k l } do_plansql_test 4.3 { SELECT y FROM terms, x2 WHERE y = term AND col = '*' } { - 0 0 1 {SCAN TABLE x2 (~1000000 rows)} - 0 1 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~0 rows)} + 0 0 1 {SCAN TABLE x2} + 0 1 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} a b c d e f g h i j k l } do_plansql_test 4.4 { SELECT y FROM x3, terms WHERE y = term AND col = '*' } { - 0 0 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} - 0 1 0 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) (~10 rows)} + 0 0 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} + 0 1 0 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)} a b c d e f g h i j k l } do_plansql_test 4.5 { SELECT y FROM terms, x3 WHERE y = term AND occurrences>1 AND col = '*' } { - 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} - 0 1 1 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) (~10 rows)} + 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} + 0 1 1 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)} a k l } @@ -519,4 +519,3 @@ do_test 8.2 { } {1 {SQL logic error or missing database}} finish_test - diff --git a/test/fts3aux2.test b/test/fts3aux2.test new file mode 100644 index 0000000..e108fc4 --- /dev/null +++ b/test/fts3aux2.test @@ -0,0 +1,144 @@ +# 2011 January 27 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS3 module. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +ifcapable !fts3 { finish_test ; return } +set ::testprefix fts3aux2 + +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE t1 USING fts4(a, b, languageid=l); + INSERT INTO t1(a, b, l) VALUES + ('zero zero', 'zero zero', 0), + ('one two', 'three four', 1), + ('five six', 'seven eight', 2) + ; + CREATE VIRTUAL TABLE terms USING fts4aux(t1); +} {} + +do_execsql_test 1.2.1 { + SELECT term, documents, occurrences, languageid FROM terms WHERE col = '*'; +} {zero 1 4 0} + +do_execsql_test 1.2.2 { + SELECT * FROM terms; +} {zero * 1 4 zero 0 1 2 zero 1 1 2} + +do_execsql_test 1.2.3 { + SELECT * FROM terms WHERE languageid=''; +} {} + +do_execsql_test 1.2.4 { + SELECT * FROM terms WHERE languageid=-1; +} {} + +do_execsql_test 1.2.5 { + SELECT * FROM terms WHERE languageid=9223372036854775807; +} {} + +do_execsql_test 1.2.6 { + SELECT * FROM terms WHERE languageid=-9223372036854775808; +} {} + +do_execsql_test 1.2.7 { + SELECT * FROM terms WHERE languageid=NULL; +} {} + +do_execsql_test 1.3.1 { + SELECT term, documents, occurrences, languageid + FROM terms WHERE col = '*' AND languageid=1; +} { + four 1 1 1 one 1 1 1 three 1 1 1 two 1 1 1 +} + +do_execsql_test 1.3.2 { + SELECT term, col, documents, occurrences, languageid + FROM terms WHERE languageid=1; +} { + four * 1 1 1 four 1 1 1 1 + one * 1 1 1 one 0 1 1 1 + three * 1 1 1 three 1 1 1 1 + two * 1 1 1 two 0 1 1 1 +} + +do_execsql_test 1.3.3 { + SELECT term, col, documents, occurrences, languageid + FROM terms WHERE languageid=1 AND term='zero' +} { +} + +do_execsql_test 1.3.4 { + SELECT term, col, documents, occurrences, languageid + FROM terms WHERE languageid='1' AND term='two' +} { + two * 1 1 1 two 0 1 1 1 +} + +do_execsql_test 1.3.5 { + SELECT term, col, documents, occurrences, languageid + FROM terms WHERE languageid='+1' AND term>'four' +} { + one * 1 1 1 one 0 1 1 1 + three * 1 1 1 three 1 1 1 1 + two * 1 1 1 two 0 1 1 1 +} + +do_execsql_test 1.4.1 { + SELECT term, documents, occurrences, languageid + FROM terms WHERE col = '*' AND languageid=2; +} { + eight 1 1 2 five 1 1 2 seven 1 1 2 six 1 1 2 +} + +do_execsql_test 1.4.2 { + SELECT term, col, documents, occurrences, languageid + FROM terms WHERE languageid=2; +} { + eight * 1 1 2 eight 1 1 1 2 + five * 1 1 2 five 0 1 1 2 + seven * 1 1 2 seven 1 1 1 2 + six * 1 1 2 six 0 1 1 2 +} + +do_execsql_test 1.4.3 { + SELECT term, col, documents, occurrences, languageid + FROM terms WHERE languageid=2 AND term='five'; +} { + five * 1 1 2 five 0 1 1 2 +} + +do_execsql_test 1.4.4 { + SELECT term, col, documents, occurrences, languageid + FROM terms WHERE term='five' AND languageid=2 +} { + five * 1 1 2 five 0 1 1 2 +} + +do_execsql_test 1.4.5 { + SELECT term, col, documents, occurrences, languageid + FROM terms WHERE term>='seven' AND languageid=2 +} { + seven * 1 1 2 seven 1 1 1 2 + six * 1 1 2 six 0 1 1 2 +} + +do_execsql_test 1.4.6 { + SELECT term, col, documents, occurrences, languageid + FROM terms WHERE term>='e' AND term<'seven' AND languageid=2 +} { + eight * 1 1 2 eight 1 1 1 2 + five * 1 1 2 five 0 1 1 2 +} + +finish_test diff --git a/test/fts3corrupt.test b/test/fts3corrupt.test index ea4c9a9..cb50e3e 100644 --- a/test/fts3corrupt.test +++ b/test/fts3corrupt.test @@ -166,4 +166,3 @@ do_test 5.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB finish_test - diff --git a/test/fts3d.test b/test/fts3d.test index 1ae992b..5c04ead 100644 --- a/test/fts3d.test +++ b/test/fts3d.test @@ -213,16 +213,17 @@ do_test fts3d-4.matches { {0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \ {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}] -check_terms_all fts3d-4.1 {a four is one test that this three two was} +puts [db eval {SELECT c FROM t1 } ] +check_terms_all fts3d-4.1 {a four is test that this was} check_doclist_all fts3d-4.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]} check_doclist_all fts3d-4.1.2 four {} check_doclist_all fts3d-4.1.3 is {[1 0[1]] [3 0[1]]} -check_doclist_all fts3d-4.1.4 one {} +#check_doclist_all fts3d-4.1.4 one {} check_doclist_all fts3d-4.1.5 test {[1 0[3]] [2 0[3]] [3 0[3]]} check_doclist_all fts3d-4.1.6 that {[2 0[0]]} check_doclist_all fts3d-4.1.7 this {[1 0[0]] [3 0[0]]} -check_doclist_all fts3d-4.1.8 three {} -check_doclist_all fts3d-4.1.9 two {} +#check_doclist_all fts3d-4.1.8 three {} +#check_doclist_all fts3d-4.1.9 two {} check_doclist_all fts3d-4.1.10 was {[2 0[1]]} check_terms fts3d-4.2 0 0 {a four test that was} @@ -239,21 +240,20 @@ check_doclist fts3d-4.3.3 0 1 is {[3 0[1]]} check_doclist fts3d-4.3.4 0 1 test {[3 0[3]]} check_doclist fts3d-4.3.5 0 1 this {[3 0[0]]} -check_terms fts3d-4.4 1 0 {a four is one test that this three two was} +check_terms fts3d-4.4 1 0 {a four is test that this was} check_doclist fts3d-4.4.1 1 0 a {[1 0[2]] [2 0[2]] [3 0[2]]} -check_doclist fts3d-4.4.2 1 0 four {[1] [2 0[4]] [3 0[4]]} +check_doclist fts3d-4.4.2 1 0 four {[2 0[4]] [3 0[4]]} check_doclist fts3d-4.4.3 1 0 is {[1 0[1]] [3 0[1]]} -check_doclist fts3d-4.4.4 1 0 one {[1] [2] [3]} +#check_doclist fts3d-4.4.4 1 0 one {[1] [2] [3]} check_doclist fts3d-4.4.5 1 0 test {[1 0[3]] [2 0[3]] [3 0[3]]} check_doclist fts3d-4.4.6 1 0 that {[2 0[0]]} check_doclist fts3d-4.4.7 1 0 this {[1 0[0]] [3 0[0]]} -check_doclist fts3d-4.4.8 1 0 three {[1] [2] [3]} -check_doclist fts3d-4.4.9 1 0 two {[1] [2] [3]} +#check_doclist fts3d-4.4.8 1 0 three {[1] [2] [3]} +#check_doclist fts3d-4.4.9 1 0 two {[1] [2] [3]} check_doclist fts3d-4.4.10 1 0 was {[2 0[1]]} # Optimize should leave the result in the level of the highest-level # prior segment. -breakpoint do_test fts3d-4.5 { execsql { SELECT OPTIMIZE(t1) FROM t1 LIMIT 1; @@ -355,6 +355,17 @@ do_test fts3d-6.5 { SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; } } {xyz_content xyz_segdir xyz_segments} + +# ALTER TABLE RENAME on an FTS3 table following an incr-merge op. +# +do_test fts3d-6.6 { + execsql { INSERT INTO xyz(xyz) VALUES('merge=2,2') } + sqlite3 db test.db + execsql { + ALTER TABLE xyz RENAME TO ott; + SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; + } +} {ott_content ott_segdir ott_segments ott_stat} finish_test diff --git a/test/fts3defer2.test b/test/fts3defer2.test index 337359a..87af524 100644 --- a/test/fts3defer2.test +++ b/test/fts3defer2.test @@ -59,6 +59,7 @@ do_execsql_test 1.2.1 { SELECT content FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)'; } {{a b c d e f a x y}} + do_execsql_test 1.2.2 { SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1, 'pcxnal')) FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)'; @@ -153,4 +154,3 @@ foreach {tn sql} { finish_test - diff --git a/test/fts3defer3.test b/test/fts3defer3.test new file mode 100644 index 0000000..a795e92 --- /dev/null +++ b/test/fts3defer3.test @@ -0,0 +1,84 @@ +# 2010 October 23 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file contains a very simple test to show that the deferred tokens +# optimization is doing something. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +ifcapable !fts3||!fts4_deferred { + finish_test + return +} +set testprefix fts3defer3 + +set nDoclist 3204 +set nDoc 800 + +# Set up a database that contains 800 rows. Each row contains the document +# "b b", except for the row with docid=200, which contains "a b". Hence +# token "b" is extremely common and token "a" is not. +# +do_test 1.1 { + execsql { + CREATE VIRTUAL TABLE t1 USING fts4; + BEGIN; + } + for {set i 1} {$i <= $nDoc} {incr i} { + set document "b b" + if {$i==200} { set document "a b" } + execsql { INSERT INTO t1 (docid, content) VALUES($i, $document) } + } + execsql COMMIT +} {} + +# Check that the db contains two doclists. A small one for "a" and a +# larger one for "b". +# +do_execsql_test 1.2 { + SELECT blockid, length(block) FROM t1_segments; +} [list 1 8 2 $nDoclist] + +# Query for 'a b'. Although this test doesn't prove so, token "b" will +# be deferred because of the very large associated doclist. +# +do_execsql_test 1.3 { + SELECT docid, content FROM t1 WHERE t1 MATCH 'a b'; +} {200 {a b}} + +# Zero out the doclist for token "b" within the database file. Now the +# only queries that use token "b" that will work are those that defer +# it. Any query that tries to use the doclist belonging to token "b" +# will fail. +# +do_test 1.4 { + set fd [db incrblob t1_segments block 2] + puts -nonewline $fd [string repeat "\00" $nDoclist] + close $fd +} {} + +# The first two queries succeed, as they defer token "b". The last one +# fails, as it tries to load the corrupt doclist. +# +do_execsql_test 1.5 { + SELECT docid, content FROM t1 WHERE t1 MATCH 'a b'; +} {200 {a b}} +do_execsql_test 1.6 { + SELECT count(*) FROM t1 WHERE t1 MATCH 'a b'; +} {1} +do_catchsql_test 1.7 { + SELECT count(*) FROM t1 WHERE t1 MATCH 'b'; +} {1 {database disk image is malformed}} + + +finish_test diff --git a/test/fts3expr.test b/test/fts3expr.test index e7c4f65..6e23faf 100644 --- a/test/fts3expr.test +++ b/test/fts3expr.test @@ -28,6 +28,7 @@ set sqlite_fts3_enable_parentheses 1 proc test_fts3expr {expr} { db one {SELECT fts3_exprtest('simple', $expr, 'a', 'b', 'c')} } + do_test fts3expr-1.0 { test_fts3expr "abcd" } {PHRASE 3 0 abcd} @@ -495,5 +496,22 @@ do_test fts3expr-7.1 { } {} +do_test fts3expr-8.0 { test_fts3expr "(blah)" } {PHRASE 3 0 blah} +do_test fts3expr-8.1 { test_fts3expr "(blah.)" } {PHRASE 3 0 blah} +do_test fts3expr-8.2 { test_fts3expr "(blah,)" } {PHRASE 3 0 blah} +do_test fts3expr-8.3 { test_fts3expr "(blah!)" } {PHRASE 3 0 blah} +do_test fts3expr-8.4 { test_fts3expr "(blah-)" } {PHRASE 3 0 blah} + +do_test fts3expr-8.5 { test_fts3expr "((blah.))" } {PHRASE 3 0 blah} +do_test fts3expr-8.6 { test_fts3expr "(((blah,)))" } {PHRASE 3 0 blah} +do_test fts3expr-8.7 { test_fts3expr "((((blah!))))" } {PHRASE 3 0 blah} + +do_test fts3expr-8.8 { test_fts3expr "(,(blah-),)" } {PHRASE 3 0 blah} + set sqlite_fts3_enable_parentheses 0 + +do_test fts3expr-9.1 { + test_fts3expr "f (e NEAR/2 a)" +} {AND {PHRASE 3 0 f} {NEAR/2 {PHRASE 3 0 e} {PHRASE 3 0 a}}} + finish_test diff --git a/test/fts3expr3.test b/test/fts3expr3.test index e3cc261..a8d7319 100644 --- a/test/fts3expr3.test +++ b/test/fts3expr3.test @@ -204,7 +204,3 @@ do_faultsim_test fts3expr3-fault-1 -faults oom-* -body { set sqlite_fts3_enable_parentheses 0 finish_test - - - - diff --git a/test/fts3expr4.test b/test/fts3expr4.test new file mode 100644 index 0000000..9473797 --- /dev/null +++ b/test/fts3expr4.test @@ -0,0 +1,57 @@ +# 2014 May 7 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS3 module. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fts3expr4 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3||!icu { + finish_test + return +} + +set sqlite_fts3_enable_parentheses 1 + +proc test_icu_fts3expr {expr} { + db one {SELECT fts3_exprtest('icu', $expr, 'a', 'b', 'c')} +} + +proc do_icu_expr_test {tn expr res} { + uplevel [list do_test $tn [list test_icu_fts3expr $expr] $res] +} + +#------------------------------------------------------------------------- +# +do_icu_expr_test 1.1 "abcd" {PHRASE 3 0 abcd} +do_icu_expr_test 1.2 " tag " {PHRASE 3 0 tag} +do_icu_expr_test 1.3 {"x y z"} {PHRASE 3 0 x y z} +do_icu_expr_test 1.4 {x OR y} {OR {PHRASE 3 0 x} {PHRASE 3 0 y}} +do_icu_expr_test 1.5 {(x OR y)} {OR {PHRASE 3 0 x} {PHRASE 3 0 y}} +do_icu_expr_test 1.6 { "(x OR y)" } {PHRASE 3 0 ( x or y )} + +# In "col:word", if "col" is not the name of a column, the entire thing +# is passed to the tokenizer. +# +do_icu_expr_test 1.7 {a:word} {PHRASE 0 0 word} +do_icu_expr_test 1.8 {d:word} {PHRASE 3 0 d:word} + +set sqlite_fts3_enable_parentheses 0 + +do_icu_expr_test 2.1 { + f (e NEAR/2 a) +} {AND {AND {AND {PHRASE 3 0 f} {PHRASE 3 0 (}} {NEAR/2 {PHRASE 3 0 e} {PHRASE 3 0 a}}} {PHRASE 3 0 )}} + +finish_test + diff --git a/test/fts3join.test b/test/fts3join.test new file mode 100644 index 0000000..6436363 --- /dev/null +++ b/test/fts3join.test @@ -0,0 +1,66 @@ +# 2014 January 4 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS3 module. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix fts3join + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE ft1 USING fts4(x); + INSERT INTO ft1 VALUES('aaa aaa'); + INSERT INTO ft1 VALUES('aaa bbb'); + INSERT INTO ft1 VALUES('bbb aaa'); + INSERT INTO ft1 VALUES('bbb bbb'); + + CREATE TABLE t1(id, y); + INSERT INTO t1 VALUES(1, 'aaa'); + INSERT INTO t1 VALUES(2, 'bbb'); +} + +do_execsql_test 1.1 { + SELECT docid FROM ft1, t1 WHERE ft1 MATCH y AND id=1; +} {1 2 3} + +do_execsql_test 1.2 { + SELECT docid FROM ft1, t1 WHERE ft1 MATCH y AND id=1 ORDER BY docid; +} {1 2 3} + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE ft2 USING fts4(x); + CREATE VIRTUAL TABLE ft3 USING fts4(y); + + INSERT INTO ft2 VALUES('abc'); + INSERT INTO ft2 VALUES('def'); + INSERT INTO ft3 VALUES('ghi'); + INSERT INTO ft3 VALUES('abc'); +} + +do_execsql_test 2.1 { SELECT * FROM ft2, ft3 WHERE x MATCH y; } {abc abc} +do_execsql_test 2.2 { SELECT * FROM ft2, ft3 WHERE y MATCH x; } {abc abc} +do_execsql_test 2.3 { SELECT * FROM ft3, ft2 WHERE x MATCH y; } {abc abc} +do_execsql_test 2.4 { SELECT * FROM ft3, ft2 WHERE y MATCH x; } {abc abc} + +do_catchsql_test 2.5 { + SELECT * FROM ft3, ft2 WHERE y MATCH x AND x MATCH y; +} {1 {unable to use function MATCH in the requested context}} + +finish_test + + diff --git a/test/fts3malloc.test b/test/fts3malloc.test index 7eeee7f..ed30fe2 100644 --- a/test/fts3malloc.test +++ b/test/fts3malloc.test @@ -62,6 +62,9 @@ do_error_test fts3_malloc-1.5 { do_write_test fts3_malloc-1.6 sqlite_master { CREATE VIRTUAL TABLE ft6 USING fts3(a, b, tokenize porter) } +do_write_test fts3_malloc-1.7 sqlite_master { + CREATE VIRTUAL TABLE ft7 USING fts4(a, b, notindexed=b) +} # Test the xConnect/xDisconnect methods: #db eval { ATTACH 'test2.db' AS aux } @@ -81,6 +84,7 @@ do_test fts3_malloc-2.0 { DROP TABLE ft3; DROP TABLE ft4; DROP TABLE ft6; + DROP TABLE ft7; } execsql { CREATE VIRTUAL TABLE ft USING fts3(a, b) } for {set ii 1} {$ii < 32} {incr ii} { @@ -301,4 +305,3 @@ do_write_test fts3_malloc-5.3 ft_content { finish_test - diff --git a/test/fts3matchinfo.test b/test/fts3matchinfo.test index 3998c9a..fd475af 100644 --- a/test/fts3matchinfo.test +++ b/test/fts3matchinfo.test @@ -426,5 +426,11 @@ do_execsql_test 8.3 { {0 3 2 0 3 2 1 4 3} {1 3 2 1 3 2 1 4 3} {2 3 2 2 3 2 2 4 3} } -finish_test +do_execsql_test 9.1 { + CREATE VIRTUAL TABLE ft2 USING fts4; + INSERT INTO ft2 VALUES('a b c d e'); + INSERT INTO ft2 VALUES('f a b c d'); + SELECT snippet(ft2, '[', ']', '', -1, 1) FROM ft2 WHERE ft2 MATCH 'c'; +} {{[c]} {[c]}} +finish_test diff --git a/test/fts3near.test b/test/fts3near.test index 9276fa3..2d9981e 100644 --- a/test/fts3near.test +++ b/test/fts3near.test @@ -165,7 +165,6 @@ do_test fts3near-3.6 { SELECT offsets(t1) FROM t1 WHERE content MATCH 'three NEAR/0 "two four"' } } {{0 0 8 5 0 1 14 3 0 2 18 4}} -breakpoint do_test fts3near-3.7 { execsql { SELECT offsets(t1) FROM t1 WHERE content MATCH '"two four" NEAR/0 three'} diff --git a/test/fts3prefix2.test b/test/fts3prefix2.test index e3da3b7..e033fb6 100644 --- a/test/fts3prefix2.test +++ b/test/fts3prefix2.test @@ -59,4 +59,3 @@ do_execsql_test 1.3 { } finish_test - diff --git a/test/fts3query.test b/test/fts3query.test index c8f8686..2d12351 100644 --- a/test/fts3query.test +++ b/test/fts3query.test @@ -118,26 +118,26 @@ do_test fts3query-4.1 { do_eqp_test fts3query-4.2 { SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date } { - 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 1 {SCAN TABLE ft VIRTUAL TABLE INDEX 1: (~0 rows)} + 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} + 0 1 1 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:} } do_eqp_test fts3query-4.3 { SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date } { - 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 0 {SCAN TABLE ft VIRTUAL TABLE INDEX 1: (~0 rows)} + 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1} + 0 1 0 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:} } do_eqp_test fts3query-4.4 { SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date } { - 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 1 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} + 0 1 1 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test fts3query-4.5 { SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date } { - 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 0 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1} + 0 1 0 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)} } @@ -210,4 +210,3 @@ do_select_tests 6.2 { finish_test - diff --git a/test/fts3shared.test b/test/fts3shared.test index 5f75bd5..0943c05 100644 --- a/test/fts3shared.test +++ b/test/fts3shared.test @@ -1,3 +1,4 @@ +# # 2010 September 17 # # May you do good and not evil. @@ -5,6 +6,9 @@ # May you share freely, never taking more than you give. # #*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is the interactions between the FTS3/4 module +# and shared-cache mode. # set testdir [file dirname $argv0] @@ -14,6 +18,7 @@ ifcapable !fts3||!shared_cache { finish_test return } +set ::testprefix fts3shared db close set ::enable_shared_cache [sqlite3_enable_shared_cache 1] @@ -67,6 +72,105 @@ do_test fts3shared-1.6 { sqlite3_get_autocommit db2 } 0 db close db2 close +#------------------------------------------------------------------------- +# The following tests - fts3shared-2.* - test that unless FTS is bypassed +# and the underlying tables accessed directly, it is not possible for an +# SQLITE_LOCKED error to be enountered when committing an FTS transaction. +# +# Any SQLITE_LOCKED error should be returned when the fts4 (or fts4aux) +# table is first read/written within a transaction, not later on. +# +set LOCKED {1 {database table is locked}} +forcedelete test.db +sqlite3 dbR test.db +sqlite3 dbW test.db +do_test 2.1 { + execsql { + CREATE VIRTUAL TABLE t1 USING fts4; + CREATE TABLE t2ext(a, b); + CREATE VIRTUAL TABLE t2 USING fts4(content=t2ext); + CREATE VIRTUAL TABLE t1aux USING fts4aux(t1); + CREATE VIRTUAL TABLE t2aux USING fts4aux(t2); + + INSERT INTO t1 VALUES('a b c'); + INSERT INTO t2(rowid, a, b) VALUES(1, 'd e f', 'g h i'); + } dbW +} {} + +# Test that once [dbW] has written to the FTS table, no client may read +# from the FTS or fts4aux table. +do_test 2.2.1 { + execsql { + BEGIN; + INSERT INTO t1 VALUES('j k l'); + } dbW + execsql BEGIN dbR +} {} +do_test 2.2.2 { catchsql "SELECT * FROM t1 WHERE rowid=1" dbR } $LOCKED +do_test 2.2.3 { catchsql "SELECT * FROM t1 WHERE t1 MATCH 'a'" dbR } $LOCKED +do_test 2.2.4 { catchsql "SELECT rowid FROM t1 WHERE t1 MATCH 'a'" dbR } $LOCKED +do_test 2.2.5 { catchsql "SELECT * FROM t1" dbR } $LOCKED +do_test 2.2.6 { catchsql "SELECT * FROM t1aux" dbR } $LOCKED +do_test 2.2.7 { execsql COMMIT dbW } {} +do_test 2.2.8 { execsql COMMIT dbR } {} + +# Same test as 2.2.*, except with a content= table. +# +do_test 2.3.1 { + execsql { + BEGIN; + INSERT INTO t2(rowid, a, b) VALUES(2, 'j k l', 'm n o'); + } dbW + execsql BEGIN dbR +} {} +do_test 2.3.3 { catchsql "SELECT * FROM t2 WHERE t2 MATCH 'a'" dbR } $LOCKED +do_test 2.3.4 { catchsql "SELECT rowid FROM t2 WHERE t2 MATCH 'a'" dbR } $LOCKED +do_test 2.3.6 { catchsql "SELECT * FROM t2aux" dbR } $LOCKED +do_test 2.3.7 { execsql COMMIT dbW } {} +do_test 2.3.8 { execsql COMMIT dbR } {} + +# Test that once a connection has read from the FTS or fts4aux table, +# another connection may not write to the FTS table. +# +foreach {tn sql} { + 1 "SELECT * FROM t1 WHERE rowid=1" + 2 "SELECT * FROM t1 WHERE t1 MATCH 'a'" + 3 "SELECT rowid FROM t1 WHERE t1 MATCH 'a'" + 4 "SELECT * FROM t1" + 5 "SELECT * FROM t1aux" +} { + + do_test 2.4.$tn { + execsql BEGIN dbR + execsql $::sql dbR + execsql BEGIN dbW + catchsql "INSERT INTO t1 VALUES('p q r')" dbW + } $LOCKED + + execsql ROLLBACK dbR + execsql ROLLBACK dbW +} + +# Same test as 2.4.*, except with a content= table. +# +foreach {tn sql} { + 2 "SELECT * FROM t2 WHERE t2 MATCH 'a'" + 3 "SELECT rowid FROM t2 WHERE t2 MATCH 'a'" + 5 "SELECT * FROM t2aux" +} { + + do_test 2.5.$tn { + execsql BEGIN dbR + execsql $::sql dbR + execsql BEGIN dbW + catchsql "INSERT INTO t2(rowid, a, b) VALUES(3, 's t u', 'v w x')" dbW + } $LOCKED + + execsql ROLLBACK dbR + execsql ROLLBACK dbW +} + +dbW close +dbR close sqlite3_enable_shared_cache $::enable_shared_cache finish_test - diff --git a/test/fts3snippet.test b/test/fts3snippet.test index b8646cd..415251d 100644 --- a/test/fts3snippet.test +++ b/test/fts3snippet.test @@ -16,6 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix fts3snippet # If SQLITE_ENABLE_FTS3 is not defined, omit this file. ifcapable !fts3 { finish_test ; return } @@ -138,7 +139,7 @@ foreach {DO_MALLOC_TEST enc} { # Set variable $T to the test name prefix for this iteration of the loop. # - set T "fts3snippet-$enc" + set T "fts3snippet-1.$enc" ########################################################################## # Test the offset function. @@ -432,10 +433,10 @@ foreach {DO_MALLOC_TEST enc} { {2 2 1 3 3 3 6 3 0 0 0 2 3 2} }] - # EVIDENCE-OF: R-40630-02268 If used within a SELECT that uses the
- # "query by rowid" or "linear scan" strategies, then the snippet and
- # offsets both return an empty string, and the matchinfo function
- # returns a blob value zero bytes in size.
+ # EVIDENCE-OF: R-40630-02268 If used within a SELECT that uses the + # "query by rowid" or "linear scan" strategies, then the snippet and + # offsets both return an empty string, and the matchinfo function + # returns a blob value zero bytes in size. # set r 1000000 ;# A rowid that exists in table ft do_select_test $T.10.0 { SELECT rowid FROM ft WHERE rowid = $r } $r @@ -459,5 +460,65 @@ foreach {DO_MALLOC_TEST enc} { } {0 blob} } +#------------------------------------------------------------------------- +# Test an interaction between the snippet() function and OR clauses. +# +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE t2 USING fts4; + INSERT INTO t2 VALUES('one two three four five'); + INSERT INTO t2 VALUES('two three four five one'); + INSERT INTO t2 VALUES('three four five one two'); + INSERT INTO t2 VALUES('four five one two three'); + INSERT INTO t2 VALUES('five one two three four'); +} + +do_execsql_test 2.2 { + SELECT snippet(t2, '[', ']') FROM t2 WHERE t2 MATCH 'one OR (four AND six)' +} { + {[one] two three [four] five} + {two three [four] five [one]} + {three [four] five [one] two} + {[four] five [one] two three} + {five [one] two three [four]} +} + +do_execsql_test 2.3 { + SELECT snippet(t2, '[', ']') FROM t2 + WHERE t2 MATCH 'one OR (four AND six)' + ORDER BY docid DESC +} { + {five [one] two three [four]} + {[four] five [one] two three} + {three [four] five [one] two} + {two three [four] five [one]} + {[one] two three [four] five} +} + +do_execsql_test 2.4 { + INSERT INTO t2 VALUES('six'); +} + +do_execsql_test 2.5 { + SELECT snippet(t2, '[', ']') FROM t2 WHERE t2 MATCH 'one OR (four AND six)' +} { + {[one] two three [four] five} + {two three [four] five [one]} + {three [four] five [one] two} + {[four] five [one] two three} + {five [one] two three [four]} +} + +do_execsql_test 2.6 { + SELECT snippet(t2, '[', ']') FROM t2 + WHERE t2 MATCH 'one OR (four AND six)' + ORDER BY docid DESC +} { + {five [one] two three [four]} + {[four] five [one] two three} + {three [four] five [one] two} + {two three [four] five [one]} + {[one] two three [four] five} +} + set sqlite_fts3_enable_parentheses 0 finish_test diff --git a/test/fts3sort.test b/test/fts3sort.test index be75604..218bf3e 100644 --- a/test/fts3sort.test +++ b/test/fts3sort.test @@ -182,4 +182,3 @@ do_execsql_test 3.2 { finish_test - diff --git a/test/fts3tok1.test b/test/fts3tok1.test index 98e55a0..e6fbbe1 100644 --- a/test/fts3tok1.test +++ b/test/fts3tok1.test @@ -90,7 +90,6 @@ do_execsql_test 1.13.1 { INSERT INTO c1(x) VALUES('a b c'); INSERT INTO c1(x) VALUES('d e f'); } -breakpoint do_execsql_test 1.13.2 { SELECT * FROM c1, t1 WHERE input = x AND c1.rowid=t1.rowid; } { @@ -113,5 +112,3 @@ do_catchsql_test 2.1 { finish_test - - diff --git a/test/fts3tok_err.test b/test/fts3tok_err.test index aaa7272..df0d4be 100644 --- a/test/fts3tok_err.test +++ b/test/fts3tok_err.test @@ -45,5 +45,3 @@ do_faultsim_test fts3tok_err-2 -faults oom* -prep { finish_test - - diff --git a/test/fts3varint.test b/test/fts3varint.test new file mode 100644 index 0000000..ca0189d --- /dev/null +++ b/test/fts3varint.test @@ -0,0 +1,118 @@ +# 2007 November 23 +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file runs all tests. +# +# $Id: fts3.test,v 1.2 2008/07/23 18:17:32 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fts3varint + +ifcapable !fts3 { + finish_test + return +} + +proc test_list {list} { + foreach n $list { fts3_test_varint $n } +} + +proc do_fts3_varint_test {tn list} { + uplevel [list do_test $tn [list test_list $list] {}] +} + +do_fts3_varint_test 1.0 { + 1 10 100 1000 10000 100000 1000000 + 10000000 100000000 1000000000 10000000000 + 100000000000 1000000000000 10000000000000 +} + +do_fts3_varint_test 1.1 { + -1 -10 -100 -1000 -10000 -100000 -1000000 + -10000000 -100000000 -1000000000 -10000000000 + -100000000000 -1000000000000 -10000000000000 +} + +do_fts3_varint_test 2.0 { 0 1 2 } +do_fts3_varint_test 2.1 { 1 2 3 } +do_fts3_varint_test 2.2 { 3 4 5 } +do_fts3_varint_test 2.3 { 7 8 9 } +do_fts3_varint_test 2.4 { 15 16 17 } +do_fts3_varint_test 2.5 { 31 32 33 } +do_fts3_varint_test 2.6 { 63 64 65 } +do_fts3_varint_test 2.7 { 127 128 129 } +do_fts3_varint_test 2.8 { 255 256 257 } +do_fts3_varint_test 2.9 { 511 512 513 } +do_fts3_varint_test 2.10 { 1023 1024 1025 } +do_fts3_varint_test 2.11 { 2047 2048 2049 } +do_fts3_varint_test 2.12 { 4095 4096 4097 } +do_fts3_varint_test 2.13 { 8191 8192 8193 } +do_fts3_varint_test 2.14 { 16383 16384 16385 } +do_fts3_varint_test 2.15 { 32767 32768 32769 } +do_fts3_varint_test 2.16 { 65535 65536 65537 } +do_fts3_varint_test 2.17 { 131071 131072 131073 } +do_fts3_varint_test 2.18 { 262143 262144 262145 } +do_fts3_varint_test 2.19 { 524287 524288 524289 } +do_fts3_varint_test 2.20 { 1048575 1048576 1048577 } +do_fts3_varint_test 2.21 { 2097151 2097152 2097153 } +do_fts3_varint_test 2.22 { 4194303 4194304 4194305 } +do_fts3_varint_test 2.23 { 8388607 8388608 8388609 } +do_fts3_varint_test 2.24 { 16777215 16777216 16777217 } +do_fts3_varint_test 2.25 { 33554431 33554432 33554433 } +do_fts3_varint_test 2.26 { 67108863 67108864 67108865 } +do_fts3_varint_test 2.27 { 134217727 134217728 134217729 } +do_fts3_varint_test 2.28 { 268435455 268435456 268435457 } +do_fts3_varint_test 2.29 { 536870911 536870912 536870913 } +do_fts3_varint_test 2.30 { 1073741823 1073741824 1073741825 } +do_fts3_varint_test 2.31 { 2147483647 2147483648 2147483649 } +do_fts3_varint_test 2.32 { 4294967295 4294967296 4294967297 } +do_fts3_varint_test 2.33 { 8589934591 8589934592 8589934593 } +do_fts3_varint_test 2.34 { 17179869183 17179869184 17179869185 } +do_fts3_varint_test 2.35 { 34359738367 34359738368 34359738369 } +do_fts3_varint_test 2.36 { 68719476735 68719476736 68719476737 } +do_fts3_varint_test 2.37 { 137438953471 137438953472 137438953473 } +do_fts3_varint_test 2.38 { 274877906943 274877906944 274877906945 } +do_fts3_varint_test 2.39 { 549755813887 549755813888 549755813889 } +do_fts3_varint_test 2.40 { 1099511627775 1099511627776 1099511627777 } +do_fts3_varint_test 2.41 { 2199023255551 2199023255552 2199023255553 } +do_fts3_varint_test 2.42 { 4398046511103 4398046511104 4398046511105 } +do_fts3_varint_test 2.43 { 8796093022207 8796093022208 8796093022209 } +do_fts3_varint_test 2.44 { 17592186044415 17592186044416 17592186044417 } +do_fts3_varint_test 2.45 { 35184372088831 35184372088832 35184372088833 } +do_fts3_varint_test 2.46 { 70368744177663 70368744177664 70368744177665 } +do_fts3_varint_test 2.47 { 140737488355327 140737488355328 140737488355329 } +do_fts3_varint_test 2.48 { 281474976710655 281474976710656 281474976710657 } +do_fts3_varint_test 2.49 { 562949953421311 562949953421312 562949953421313 } +do_fts3_varint_test 2.50 { 1125899906842623 1125899906842624 1125899906842625 } +do_fts3_varint_test 2.51 { 2251799813685247 2251799813685248 2251799813685249 } +do_fts3_varint_test 2.52 { 4503599627370495 4503599627370496 4503599627370497 } +do_fts3_varint_test 2.53 { 9007199254740991 9007199254740992 9007199254740993 } +do_fts3_varint_test 2.54 { + 18014398509481983 18014398509481984 18014398509481985 } +do_fts3_varint_test 2.55 { + 36028797018963967 36028797018963968 36028797018963969 } +do_fts3_varint_test 2.56 { + 72057594037927935 72057594037927936 72057594037927937 } +do_fts3_varint_test 2.57 { + 144115188075855871 144115188075855872 144115188075855873 } +do_fts3_varint_test 2.58 { + 288230376151711743 288230376151711744 288230376151711745 } +do_fts3_varint_test 2.59 { + 576460752303423487 576460752303423488 576460752303423489 } +do_fts3_varint_test 2.60 { + 1152921504606846975 1152921504606846976 1152921504606846977 } +do_fts3_varint_test 2.61 { + 2305843009213693951 2305843009213693952 2305843009213693953 } +do_fts3_varint_test 2.62 { + 4611686018427387903 4611686018427387904 4611686018427387905 } +do_fts3_varint_test 2.63 { + 9223372036854775807 9223372036854775808 9223372036854775809 } + +do_fts3_varint_test 3.0 { 18446744073709551615 -18446744073709551615 } + +finish_test diff --git a/test/fts4aa.test b/test/fts4aa.test index 2e6baf8..88550c9 100644 --- a/test/fts4aa.test +++ b/test/fts4aa.test @@ -22,1548 +22,10 @@ ifcapable !fts3 { return } -# This procedure fills an existing FTS3/FTS4 table with many entries. -# The table needs to have a single column (other than docid) named "words". +# Create the fts_kjv_genesis procedure which fills and FTS3/4 table with +# the complete text of the Book of Genesis. # -proc fts4aa_fill_table {} { -db eval { -BEGIN TRANSACTION; -INSERT INTO t1(docid,words) VALUES(1001001,'In the beginning God created the heaven and the earth.'); -INSERT INTO t1(docid,words) VALUES(1001002,'And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.'); -INSERT INTO t1(docid,words) VALUES(1001003,'And God said, Let there be light: and there was light.'); -INSERT INTO t1(docid,words) VALUES(1001004,'And God saw the light, that it was good: and God divided the light from the darkness.'); -INSERT INTO t1(docid,words) VALUES(1001005,'And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day.'); -INSERT INTO t1(docid,words) VALUES(1001006,'And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters.'); -INSERT INTO t1(docid,words) VALUES(1001007,'And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so.'); -INSERT INTO t1(docid,words) VALUES(1001008,'And God called the firmament Heaven. And the evening and the morning were the second day.'); -INSERT INTO t1(docid,words) VALUES(1001009,'And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so.'); -INSERT INTO t1(docid,words) VALUES(1001010,'And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good.'); -INSERT INTO t1(docid,words) VALUES(1001011,'And God said, Let the earth bring forth grass, the herb yielding seed, and the fruit tree yielding fruit after his kind, whose seed is in itself, upon the earth: and it was so.'); -INSERT INTO t1(docid,words) VALUES(1001012,'And the earth brought forth grass, and herb yielding seed after his kind, and the tree yielding fruit, whose seed was in itself, after his kind: and God saw that it was good.'); -INSERT INTO t1(docid,words) VALUES(1001013,'And the evening and the morning were the third day.'); -INSERT INTO t1(docid,words) VALUES(1001014,'And God said, Let there be lights in the firmament of the heaven to divide the day from the night; and let them be for signs, and for seasons, and for days, and years:'); -INSERT INTO t1(docid,words) VALUES(1001015,'And let them be for lights in the firmament of the heaven to give light upon the earth: and it was so.'); -INSERT INTO t1(docid,words) VALUES(1001016,'And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: he made the stars also.'); -INSERT INTO t1(docid,words) VALUES(1001017,'And God set them in the firmament of the heaven to give light upon the earth,'); -INSERT INTO t1(docid,words) VALUES(1001018,'And to rule over the day and over the night, and to divide the light from the darkness: and God saw that it was good.'); -INSERT INTO t1(docid,words) VALUES(1001019,'And the evening and the morning were the fourth day.'); -INSERT INTO t1(docid,words) VALUES(1001020,'And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl that may fly above the earth in the open firmament of heaven.'); -INSERT INTO t1(docid,words) VALUES(1001021,'And God created great whales, and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that it was good.'); -INSERT INTO t1(docid,words) VALUES(1001022,'And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth.'); -INSERT INTO t1(docid,words) VALUES(1001023,'And the evening and the morning were the fifth day.'); -INSERT INTO t1(docid,words) VALUES(1001024,'And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so.'); -INSERT INTO t1(docid,words) VALUES(1001025,'And God made the beast of the earth after his kind, and cattle after their kind, and every thing that creepeth upon the earth after his kind: and God saw that it was good.'); -INSERT INTO t1(docid,words) VALUES(1001026,'And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth.'); -INSERT INTO t1(docid,words) VALUES(1001027,'So God created man in his own image, in the image of God created he him; male and female created he them.'); -INSERT INTO t1(docid,words) VALUES(1001028,'And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth.'); -INSERT INTO t1(docid,words) VALUES(1001029,'And God said, Behold, I have given you every herb bearing seed, which is upon the face of all the earth, and every tree, in the which is the fruit of a tree yielding seed; to you it shall be for meat.'); -INSERT INTO t1(docid,words) VALUES(1001030,'And to every beast of the earth, and to every fowl of the air, and to every thing that creepeth upon the earth, wherein there is life, I have given every green herb for meat: and it was so.'); -INSERT INTO t1(docid,words) VALUES(1001031,'And God saw every thing that he had made, and, behold, it was very good. And the evening and the morning were the sixth day.'); -INSERT INTO t1(docid,words) VALUES(1002001,'Thus the heavens and the earth were finished, and all the host of them.'); -INSERT INTO t1(docid,words) VALUES(1002002,'And on the seventh day God ended his work which he had made; and he rested on the seventh day from all his work which he had made.'); -INSERT INTO t1(docid,words) VALUES(1002003,'And God blessed the seventh day, and sanctified it: because that in it he had rested from all his work which God created and made.'); -INSERT INTO t1(docid,words) VALUES(1002004,'These are the generations of the heavens and of the earth when they were created, in the day that the LORD God made the earth and the heavens,'); -INSERT INTO t1(docid,words) VALUES(1002005,'And every plant of the field before it was in the earth, and every herb of the field before it grew: for the LORD God had not caused it to rain upon the earth, and there was not a man to till the ground.'); -INSERT INTO t1(docid,words) VALUES(1002006,'But there went up a mist from the earth, and watered the whole face of the ground.'); -INSERT INTO t1(docid,words) VALUES(1002007,'And the LORD God formed man of the dust of the ground, and breathed into his nostrils the breath of life; and man became a living soul.'); -INSERT INTO t1(docid,words) VALUES(1002008,'And the LORD God planted a garden eastward in Eden; and there he put the man whom he had formed.'); -INSERT INTO t1(docid,words) VALUES(1002009,'And out of the ground made the LORD God to grow every tree that is pleasant to the sight, and good for food; the tree of life also in the midst of the garden, and the tree of knowledge of good and evil.'); -INSERT INTO t1(docid,words) VALUES(1002010,'And a river went out of Eden to water the garden; and from thence it was parted, and became into four heads.'); -INSERT INTO t1(docid,words) VALUES(1002011,'The name of the first is Pison: that is it which compasseth the whole land of Havilah, where there is gold;'); -INSERT INTO t1(docid,words) VALUES(1002012,'And the gold of that land is good: there is bdellium and the onyx stone.'); -INSERT INTO t1(docid,words) VALUES(1002013,'And the name of the second river is Gihon: the same is it that compasseth the whole land of Ethiopia.'); -INSERT INTO t1(docid,words) VALUES(1002014,'And the name of the third river is Hiddekel: that is it which goeth toward the east of Assyria. And the fourth river is Euphrates.'); -INSERT INTO t1(docid,words) VALUES(1002015,'And the LORD God took the man, and put him into the garden of Eden to dress it and to keep it.'); -INSERT INTO t1(docid,words) VALUES(1002016,'And the LORD God commanded the man, saying, Of every tree of the garden thou mayest freely eat:'); -INSERT INTO t1(docid,words) VALUES(1002017,'But of the tree of the knowledge of good and evil, thou shalt not eat of it: for in the day that thou eatest thereof thou shalt surely die.'); -INSERT INTO t1(docid,words) VALUES(1002018,'And the LORD God said, It is not good that the man should be alone; I will make him an help meet for him.'); -INSERT INTO t1(docid,words) VALUES(1002019,'And out of the ground the LORD God formed every beast of the field, and every fowl of the air; and brought them unto Adam to see what he would call them: and whatsoever Adam called every living creature, that was the name thereof.'); -INSERT INTO t1(docid,words) VALUES(1002020,'And Adam gave names to all cattle, and to the fowl of the air, and to every beast of the field; but for Adam there was not found an help meet for him.'); -INSERT INTO t1(docid,words) VALUES(1002021,'And the LORD God caused a deep sleep to fall upon Adam, and he slept: and he took one of his ribs, and closed up the flesh instead thereof;'); -INSERT INTO t1(docid,words) VALUES(1002022,'And the rib, which the LORD God had taken from man, made he a woman, and brought her unto the man.'); -INSERT INTO t1(docid,words) VALUES(1002023,'And Adam said, This is now bone of my bones, and flesh of my flesh: she shall be called Woman, because she was taken out of Man.'); -INSERT INTO t1(docid,words) VALUES(1002024,'Therefore shall a man leave his father and his mother, and shall cleave unto his wife: and they shall be one flesh.'); -INSERT INTO t1(docid,words) VALUES(1002025,'And they were both naked, the man and his wife, and were not ashamed.'); -INSERT INTO t1(docid,words) VALUES(1003001,'Now the serpent was more subtil than any beast of the field which the LORD God had made. And he said unto the woman, Yea, hath God said, Ye shall not eat of every tree of the garden?'); -INSERT INTO t1(docid,words) VALUES(1003002,'And the woman said unto the serpent, We may eat of the fruit of the trees of the garden:'); -INSERT INTO t1(docid,words) VALUES(1003003,'But of the fruit of the tree which is in the midst of the garden, God hath said, Ye shall not eat of it, neither shall ye touch it, lest ye die.'); -INSERT INTO t1(docid,words) VALUES(1003004,'And the serpent said unto the woman, Ye shall not surely die:'); -INSERT INTO t1(docid,words) VALUES(1003005,'For God doth know that in the day ye eat thereof, then your eyes shall be opened, and ye shall be as gods, knowing good and evil.'); -INSERT INTO t1(docid,words) VALUES(1003006,'And when the woman saw that the tree was good for food, and that it was pleasant to the eyes, and a tree to be desired to make one wise, she took of the fruit thereof, and did eat, and gave also unto her husband with her; and he did eat.'); -INSERT INTO t1(docid,words) VALUES(1003007,'And the eyes of them both were opened, and they knew that they were naked; and they sewed fig leaves together, and made themselves aprons.'); -INSERT INTO t1(docid,words) VALUES(1003008,'And they heard the voice of the LORD God walking in the garden in the cool of the day: and Adam and his wife hid themselves from the presence of the LORD God amongst the trees of the garden.'); -INSERT INTO t1(docid,words) VALUES(1003009,'And the LORD God called unto Adam, and said unto him, Where art thou?'); -INSERT INTO t1(docid,words) VALUES(1003010,'And he said, I heard thy voice in the garden, and I was afraid, because I was naked; and I hid myself.'); -INSERT INTO t1(docid,words) VALUES(1003011,'And he said, Who told thee that thou wast naked? Hast thou eaten of the tree, whereof I commanded thee that thou shouldest not eat?'); -INSERT INTO t1(docid,words) VALUES(1003012,'And the man said, The woman whom thou gavest to be with me, she gave me of the tree, and I did eat.'); -INSERT INTO t1(docid,words) VALUES(1003013,'And the LORD God said unto the woman, What is this that thou hast done? And the woman said, The serpent beguiled me, and I did eat.'); -INSERT INTO t1(docid,words) VALUES(1003014,'And the LORD God said unto the serpent, Because thou hast done this, thou art cursed above all cattle, and above every beast of the field; upon thy belly shalt thou go, and dust shalt thou eat all the days of thy life:'); -INSERT INTO t1(docid,words) VALUES(1003015,'And I will put enmity between thee and the woman, and between thy seed and her seed; it shall bruise thy head, and thou shalt bruise his heel.'); -INSERT INTO t1(docid,words) VALUES(1003016,'Unto the woman he said, I will greatly multiply thy sorrow and thy conception; in sorrow thou shalt bring forth children; and thy desire shall be to thy husband, and he shall rule over thee.'); -INSERT INTO t1(docid,words) VALUES(1003017,'And unto Adam he said, Because thou hast hearkened unto the voice of thy wife, and hast eaten of the tree, of which I commanded thee, saying, Thou shalt not eat of it: cursed is the ground for thy sake; in sorrow shalt thou eat of it all the days of thy life;'); -INSERT INTO t1(docid,words) VALUES(1003018,'Thorns also and thistles shall it bring forth to thee; and thou shalt eat the herb of the field;'); -INSERT INTO t1(docid,words) VALUES(1003019,'In the sweat of thy face shalt thou eat bread, till thou return unto the ground; for out of it wast thou taken: for dust thou art, and unto dust shalt thou return.'); -INSERT INTO t1(docid,words) VALUES(1003020,'And Adam called his wife''s name Eve; because she was the mother of all living.'); -INSERT INTO t1(docid,words) VALUES(1003021,'Unto Adam also and to his wife did the LORD God make coats of skins, and clothed them.'); -INSERT INTO t1(docid,words) VALUES(1003022,'And the LORD God said, Behold, the man is become as one of us, to know good and evil: and now, lest he put forth his hand, and take also of the tree of life, and eat, and live for ever:'); -INSERT INTO t1(docid,words) VALUES(1003023,'Therefore the LORD God sent him forth from the garden of Eden, to till the ground from whence he was taken.'); -INSERT INTO t1(docid,words) VALUES(1003024,'So he drove out the man; and he placed at the east of the garden of Eden Cherubims, and a flaming sword which turned every way, to keep the way of the tree of life.'); -INSERT INTO t1(docid,words) VALUES(1004001,'And Adam knew Eve his wife; and she conceived, and bare Cain, and said, I have gotten a man from the LORD.'); -INSERT INTO t1(docid,words) VALUES(1004002,'And she again bare his brother Abel. And Abel was a keeper of sheep, but Cain was a tiller of the ground.'); -INSERT INTO t1(docid,words) VALUES(1004003,'And in process of time it came to pass, that Cain brought of the fruit of the ground an offering unto the LORD.'); -INSERT INTO t1(docid,words) VALUES(1004004,'And Abel, he also brought of the firstlings of his flock and of the fat thereof. And the LORD had respect unto Abel and to his offering:'); -INSERT INTO t1(docid,words) VALUES(1004005,'But unto Cain and to his offering he had not respect. And Cain was very wroth, and his countenance fell.'); -INSERT INTO t1(docid,words) VALUES(1004006,'And the LORD said unto Cain, Why art thou wroth? and why is thy countenance fallen?'); -INSERT INTO t1(docid,words) VALUES(1004007,'If thou doest well, shalt thou not be accepted? and if thou doest not well, sin lieth at the door. And unto thee shall be his desire, and thou shalt rule over him.'); -INSERT INTO t1(docid,words) VALUES(1004008,'And Cain talked with Abel his brother: and it came to pass, when they were in the field, that Cain rose up against Abel his brother, and slew him.'); -INSERT INTO t1(docid,words) VALUES(1004009,'And the LORD said unto Cain, Where is Abel thy brother? And he said, I know not: Am I my brother''s keeper?'); -INSERT INTO t1(docid,words) VALUES(1004010,'And he said, What hast thou done? the voice of thy brother''s blood crieth unto me from the ground.'); -INSERT INTO t1(docid,words) VALUES(1004011,'And now art thou cursed from the earth, which hath opened her mouth to receive thy brother''s blood from thy hand;'); -INSERT INTO t1(docid,words) VALUES(1004012,'When thou tillest the ground, it shall not henceforth yield unto thee her strength; a fugitive and a vagabond shalt thou be in the earth.'); -INSERT INTO t1(docid,words) VALUES(1004013,'And Cain said unto the LORD, My punishment is greater than I can bear.'); -INSERT INTO t1(docid,words) VALUES(1004014,'Behold, thou hast driven me out this day from the face of the earth; and from thy face shall I be hid; and I shall be a fugitive and a vagabond in the earth; and it shall come to pass, that every one that findeth me shall slay me.'); -INSERT INTO t1(docid,words) VALUES(1004015,'And the LORD said unto him, Therefore whosoever slayeth Cain, vengeance shall be taken on him sevenfold. And the LORD set a mark upon Cain, lest any finding him should kill him.'); -INSERT INTO t1(docid,words) VALUES(1004016,'And Cain went out from the presence of the LORD, and dwelt in the land of Nod, on the east of Eden.'); -INSERT INTO t1(docid,words) VALUES(1004017,'And Cain knew his wife; and she conceived, and bare Enoch: and he builded a city, and called the name of the city, after the name of his son, Enoch.'); -INSERT INTO t1(docid,words) VALUES(1004018,'And unto Enoch was born Irad: and Irad begat Mehujael: and Mehujael begat Methusael: and Methusael begat Lamech.'); -INSERT INTO t1(docid,words) VALUES(1004019,'And Lamech took unto him two wives: the name of the one was Adah, and the name of the other Zillah.'); -INSERT INTO t1(docid,words) VALUES(1004020,'And Adah bare Jabal: he was the father of such as dwell in tents, and of such as have cattle.'); -INSERT INTO t1(docid,words) VALUES(1004021,'And his brother''s name was Jubal: he was the father of all such as handle the harp and organ.'); -INSERT INTO t1(docid,words) VALUES(1004022,'And Zillah, she also bare Tubalcain, an instructer of every artificer in brass and iron: and the sister of Tubalcain was Naamah.'); -INSERT INTO t1(docid,words) VALUES(1004023,'And Lamech said unto his wives, Adah and Zillah, Hear my voice; ye wives of Lamech, hearken unto my speech: for I have slain a man to my wounding, and a young man to my hurt.'); -INSERT INTO t1(docid,words) VALUES(1004024,'If Cain shall be avenged sevenfold, truly Lamech seventy and sevenfold.'); -INSERT INTO t1(docid,words) VALUES(1004025,'And Adam knew his wife again; and she bare a son, and called his name Seth: For God, said she, hath appointed me another seed instead of Abel, whom Cain slew.'); -INSERT INTO t1(docid,words) VALUES(1004026,'And to Seth, to him also there was born a son; and he called his name Enos: then began men to call upon the name of the LORD.'); -INSERT INTO t1(docid,words) VALUES(1005001,'This is the book of the generations of Adam. In the day that God created man, in the likeness of God made he him;'); -INSERT INTO t1(docid,words) VALUES(1005002,'Male and female created he them; and blessed them, and called their name Adam, in the day when they were created.'); -INSERT INTO t1(docid,words) VALUES(1005003,'And Adam lived an hundred and thirty years, and begat a son in his own likeness, and after his image; and called his name Seth:'); -INSERT INTO t1(docid,words) VALUES(1005004,'And the days of Adam after he had begotten Seth were eight hundred years: and he begat sons and daughters:'); -INSERT INTO t1(docid,words) VALUES(1005005,'And all the days that Adam lived were nine hundred and thirty years: and he died.'); -INSERT INTO t1(docid,words) VALUES(1005006,'And Seth lived an hundred and five years, and begat Enos:'); -INSERT INTO t1(docid,words) VALUES(1005007,'And Seth lived after he begat Enos eight hundred and seven years, and begat sons and daughters:'); -INSERT INTO t1(docid,words) VALUES(1005008,'And all the days of Seth were nine hundred and twelve years: and he died.'); -INSERT INTO t1(docid,words) VALUES(1005009,'And Enos lived ninety years, and begat Cainan:'); -INSERT INTO t1(docid,words) VALUES(1005010,'And Enos lived after he begat Cainan eight hundred and fifteen years, and begat sons and daughters:'); -INSERT INTO t1(docid,words) VALUES(1005011,'And all the days of Enos were nine hundred and five years: and he died.'); -INSERT INTO t1(docid,words) VALUES(1005012,'And Cainan lived seventy years and begat Mahalaleel:'); -INSERT INTO t1(docid,words) VALUES(1005013,'And Cainan lived after he begat Mahalaleel eight hundred and forty years, and begat sons and daughters:'); -INSERT INTO t1(docid,words) VALUES(1005014,'And all the days of Cainan were nine hundred and ten years: and he died.'); -INSERT INTO t1(docid,words) VALUES(1005015,'And Mahalaleel lived sixty and five years, and begat Jared:'); -INSERT INTO t1(docid,words) VALUES(1005016,'And Mahalaleel lived after he begat Jared eight hundred and thirty years, and begat sons and daughters:'); -INSERT INTO t1(docid,words) VALUES(1005017,'And all the days of Mahalaleel were eight hundred ninety and five years: and he died.'); -INSERT INTO t1(docid,words) VALUES(1005018,'And Jared lived an hundred sixty and two years, and he begat Enoch:'); -INSERT INTO t1(docid,words) VALUES(1005019,'And Jared lived after he begat Enoch eight hundred years, and begat sons and daughters:'); -INSERT INTO t1(docid,words) VALUES(1005020,'And all the days of Jared were nine hundred sixty and two years: and he died.'); -INSERT INTO t1(docid,words) VALUES(1005021,'And Enoch lived sixty and five years, and begat Methuselah:'); -INSERT INTO t1(docid,words) VALUES(1005022,'And Enoch walked with God after he begat Methuselah three hundred years, and begat sons and daughters:'); -INSERT INTO t1(docid,words) VALUES(1005023,'And all the days of Enoch were three hundred sixty and five years:'); -INSERT INTO t1(docid,words) VALUES(1005024,'And Enoch walked with God: and he was not; for God took him.'); -INSERT INTO t1(docid,words) VALUES(1005025,'And Methuselah lived an hundred eighty and seven years, and begat Lamech.'); -INSERT INTO t1(docid,words) VALUES(1005026,'And Methuselah lived after he begat Lamech seven hundred eighty and two years, and begat sons and daughters:'); -INSERT INTO t1(docid,words) VALUES(1005027,'And all the days of Methuselah were nine hundred sixty and nine years: and he died.'); -INSERT INTO t1(docid,words) VALUES(1005028,'And Lamech lived an hundred eighty and two years, and begat a son:'); -INSERT INTO t1(docid,words) VALUES(1005029,'And he called his name Noah, saying, This same shall comfort us concerning our work and toil of our hands, because of the ground which the LORD hath cursed.'); -INSERT INTO t1(docid,words) VALUES(1005030,'And Lamech lived after he begat Noah five hundred ninety and five years, and begat sons and daughters:'); -INSERT INTO t1(docid,words) VALUES(1005031,'And all the days of Lamech were seven hundred seventy and seven years: and he died.'); -INSERT INTO t1(docid,words) VALUES(1005032,'And Noah was five hundred years old: and Noah begat Shem, Ham, and Japheth.'); -INSERT INTO t1(docid,words) VALUES(1006001,'And it came to pass, when men began to multiply on the face of the earth, and daughters were born unto them,'); -INSERT INTO t1(docid,words) VALUES(1006002,'That the sons of God saw the daughters of men that they were fair; and they took them wives of all which they chose.'); -INSERT INTO t1(docid,words) VALUES(1006003,'And the LORD said, My spirit shall not always strive with man, for that he also is flesh: yet his days shall be an hundred and twenty years.'); -INSERT INTO t1(docid,words) VALUES(1006004,'There were giants in the earth in those days; and also after that, when the sons of God came in unto the daughters of men, and they bare children to them, the same became mighty men which were of old, men of renown.'); -INSERT INTO t1(docid,words) VALUES(1006005,'And God saw that the wickedness of man was great in the earth, and that every imagination of the thoughts of his heart was only evil continually.'); -INSERT INTO t1(docid,words) VALUES(1006006,'And it repented the LORD that he had made man on the earth, and it grieved him at his heart.'); -INSERT INTO t1(docid,words) VALUES(1006007,'And the LORD said, I will destroy man whom I have created from the face of the earth; both man, and beast, and the creeping thing, and the fowls of the air; for it repenteth me that I have made them.'); -INSERT INTO t1(docid,words) VALUES(1006008,'But Noah found grace in the eyes of the LORD.'); -INSERT INTO t1(docid,words) VALUES(1006009,'These are the generations of Noah: Noah was a just man and perfect in his generations, and Noah walked with God.'); -INSERT INTO t1(docid,words) VALUES(1006010,'And Noah begat three sons, Shem, Ham, and Japheth.'); -INSERT INTO t1(docid,words) VALUES(1006011,'The earth also was corrupt before God, and the earth was filled with violence.'); -INSERT INTO t1(docid,words) VALUES(1006012,'And God looked upon the earth, and, behold, it was corrupt; for all flesh had corrupted his way upon the earth.'); -INSERT INTO t1(docid,words) VALUES(1006013,'And God said unto Noah, The end of all flesh is come before me; for the earth is filled with violence through them; and, behold, I will destroy them with the earth.'); -INSERT INTO t1(docid,words) VALUES(1006014,'Make thee an ark of gopher wood; rooms shalt thou make in the ark, and shalt pitch it within and without with pitch.'); -INSERT INTO t1(docid,words) VALUES(1006015,'And this is the fashion which thou shalt make it of: The length of the ark shall be three hundred cubits, the breadth of it fifty cubits, and the height of it thirty cubits.'); -INSERT INTO t1(docid,words) VALUES(1006016,'A window shalt thou make to the ark, and in a cubit shalt thou finish it above; and the door of the ark shalt thou set in the side thereof; with lower, second, and third stories shalt thou make it.'); -INSERT INTO t1(docid,words) VALUES(1006017,'And, behold, I, even I, do bring a flood of waters upon the earth, to destroy all flesh, wherein is the breath of life, from under heaven; and every thing that is in the earth shall die.'); -INSERT INTO t1(docid,words) VALUES(1006018,'But with thee will I establish my covenant; and thou shalt come into the ark, thou, and thy sons, and thy wife, and thy sons'' wives with thee.'); -INSERT INTO t1(docid,words) VALUES(1006019,'And of every living thing of all flesh, two of every sort shalt thou bring into the ark, to keep them alive with thee; they shall be male and female.'); -INSERT INTO t1(docid,words) VALUES(1006020,'Of fowls after their kind, and of cattle after their kind, of every creeping thing of the earth after his kind, two of every sort shall come unto thee, to keep them alive.'); -INSERT INTO t1(docid,words) VALUES(1006021,'And take thou unto thee of all food that is eaten, and thou shalt gather it to thee; and it shall be for food for thee, and for them.'); -INSERT INTO t1(docid,words) VALUES(1006022,'Thus did Noah; according to all that God commanded him, so did he.'); -INSERT INTO t1(docid,words) VALUES(1007001,'And the LORD said unto Noah, Come thou and all thy house into the ark; for thee have I seen righteous before me in this generation.'); -INSERT INTO t1(docid,words) VALUES(1007002,'Of every clean beast thou shalt take to thee by sevens, the male and his female: and of beasts that are not clean by two, the male and his female.'); -INSERT INTO t1(docid,words) VALUES(1007003,'Of fowls also of the air by sevens, the male and the female; to keep seed alive upon the face of all the earth.'); -INSERT INTO t1(docid,words) VALUES(1007004,'For yet seven days, and I will cause it to rain upon the earth forty days and forty nights; and every living substance that I have made will I destroy from off the face of the earth.'); -INSERT INTO t1(docid,words) VALUES(1007005,'And Noah did according unto all that the LORD commanded him.'); -INSERT INTO t1(docid,words) VALUES(1007006,'And Noah was six hundred years old when the flood of waters was upon the earth.'); -INSERT INTO t1(docid,words) VALUES(1007007,'And Noah went in, and his sons, and his wife, and his sons'' wives with him, into the ark, because of the waters of the flood.'); -INSERT INTO t1(docid,words) VALUES(1007008,'Of clean beasts, and of beasts that are not clean, and of fowls, and of every thing that creepeth upon the earth,'); -INSERT INTO t1(docid,words) VALUES(1007009,'There went in two and two unto Noah into the ark, the male and the female, as God had commanded Noah.'); -INSERT INTO t1(docid,words) VALUES(1007010,'And it came to pass after seven days, that the waters of the flood were upon the earth.'); -INSERT INTO t1(docid,words) VALUES(1007011,'In the six hundredth year of Noah''s life, in the second month, the seventeenth day of the month, the same day were all the fountains of the great deep broken up, and the windows of heaven were opened.'); -INSERT INTO t1(docid,words) VALUES(1007012,'And the rain was upon the earth forty days and forty nights.'); -INSERT INTO t1(docid,words) VALUES(1007013,'In the selfsame day entered Noah, and Shem, and Ham, and Japheth, the sons of Noah, and Noah''s wife, and the three wives of his sons with them, into the ark;'); -INSERT INTO t1(docid,words) VALUES(1007014,'They, and every beast after his kind, and all the cattle after their kind, and every creeping thing that creepeth upon the earth after his kind, and every fowl after his kind, every bird of every sort.'); -INSERT INTO t1(docid,words) VALUES(1007015,'And they went in unto Noah into the ark, two and two of all flesh, wherein is the breath of life.'); -INSERT INTO t1(docid,words) VALUES(1007016,'And they that went in, went in male and female of all flesh, as God had commanded him: and the LORD shut him in.'); -INSERT INTO t1(docid,words) VALUES(1007017,'And the flood was forty days upon the earth; and the waters increased, and bare up the ark, and it was lift up above the earth.'); -INSERT INTO t1(docid,words) VALUES(1007018,'And the waters prevailed, and were increased greatly upon the earth; and the ark went upon the face of the waters.'); -INSERT INTO t1(docid,words) VALUES(1007019,'And the waters prevailed exceedingly upon the earth; and all the high hills, that were under the whole heaven, were covered.'); -INSERT INTO t1(docid,words) VALUES(1007020,'Fifteen cubits upward did the waters prevail; and the mountains were covered.'); -INSERT INTO t1(docid,words) VALUES(1007021,'And all flesh died that moved upon the earth, both of fowl, and of cattle, and of beast, and of every creeping thing that creepeth upon the earth, and every man:'); -INSERT INTO t1(docid,words) VALUES(1007022,'All in whose nostrils was the breath of life, of all that was in the dry land, died.'); -INSERT INTO t1(docid,words) VALUES(1007023,'And every living substance was destroyed which was upon the face of the ground, both man, and cattle, and the creeping things, and the fowl of the heaven; and they were destroyed from the earth: and Noah only remained alive, and they that were with him in the ark.'); -INSERT INTO t1(docid,words) VALUES(1007024,'And the waters prevailed upon the earth an hundred and fifty days.'); -INSERT INTO t1(docid,words) VALUES(1008001,'And God remembered Noah, and every living thing, and all the cattle that was with him in the ark: and God made a wind to pass over the earth, and the waters asswaged;'); -INSERT INTO t1(docid,words) VALUES(1008002,'The fountains also of the deep and the windows of heaven were stopped, and the rain from heaven was restrained;'); -INSERT INTO t1(docid,words) VALUES(1008003,'And the waters returned from off the earth continually: and after the end of the hundred and fifty days the waters were abated.'); -INSERT INTO t1(docid,words) VALUES(1008004,'And the ark rested in the seventh month, on the seventeenth day of the month, upon the mountains of Ararat.'); -INSERT INTO t1(docid,words) VALUES(1008005,'And the waters decreased continually until the tenth month: in the tenth month, on the first day of the month, were the tops of the mountains seen.'); -INSERT INTO t1(docid,words) VALUES(1008006,'And it came to pass at the end of forty days, that Noah opened the window of the ark which he had made:'); -INSERT INTO t1(docid,words) VALUES(1008007,'And he sent forth a raven, which went forth to and fro, until the waters were dried up from off the earth.'); -INSERT INTO t1(docid,words) VALUES(1008008,'Also he sent forth a dove from him, to see if the waters were abated from off the face of the ground;'); -INSERT INTO t1(docid,words) VALUES(1008009,'But the dove found no rest for the sole of her foot, and she returned unto him into the ark, for the waters were on the face of the whole earth: then he put forth his hand, and took her, and pulled her in unto him into the ark.'); -INSERT INTO t1(docid,words) VALUES(1008010,'And he stayed yet other seven days; and again he sent forth the dove out of the ark;'); -INSERT INTO t1(docid,words) VALUES(1008011,'And the dove came in to him in the evening; and, lo, in her mouth was an olive leaf pluckt off: so Noah knew that the waters were abated from off the earth.'); -INSERT INTO t1(docid,words) VALUES(1008012,'And he stayed yet other seven days; and sent forth the dove; which returned not again unto him any more.'); -INSERT INTO t1(docid,words) VALUES(1008013,'And it came to pass in the six hundredth and first year, in the first month, the first day of the month, the waters were dried up from off the earth: and Noah removed the covering of the ark, and looked, and, behold, the face of the ground was dry.'); -INSERT INTO t1(docid,words) VALUES(1008014,'And in the second month, on the seven and twentieth day of the month, was the earth dried.'); -INSERT INTO t1(docid,words) VALUES(1008015,'And God spake unto Noah, saying,'); -INSERT INTO t1(docid,words) VALUES(1008016,'Go forth of the ark, thou, and thy wife, and thy sons, and thy sons'' wives with thee.'); -INSERT INTO t1(docid,words) VALUES(1008017,'Bring forth with thee every living thing that is with thee, of all flesh, both of fowl, and of cattle, and of every creeping thing that creepeth upon the earth; that they may breed abundantly in the earth, and be fruitful, and multiply upon the earth.'); -INSERT INTO t1(docid,words) VALUES(1008018,'And Noah went forth, and his sons, and his wife, and his sons'' wives with him:'); -INSERT INTO t1(docid,words) VALUES(1008019,'Every beast, every creeping thing, and every fowl, and whatsoever creepeth upon the earth, after their kinds, went forth out of the ark.'); -INSERT INTO t1(docid,words) VALUES(1008020,'And Noah builded an altar unto the LORD; and took of every clean beast, and of every clean fowl, and offered burnt offerings on the altar.'); -INSERT INTO t1(docid,words) VALUES(1008021,'And the LORD smelled a sweet savour; and the LORD said in his heart, I will not again curse the ground any more for man''s sake; for the imagination of man''s heart is evil from his youth; neither will I again smite any more every thing living, as I have done.'); -INSERT INTO t1(docid,words) VALUES(1008022,'While the earth remaineth, seedtime and harvest, and cold and heat, and summer and winter, and day and night shall not cease.'); -INSERT INTO t1(docid,words) VALUES(1009001,'And God blessed Noah and his sons, and said unto them, Be fruitful, and multiply, and replenish the earth.'); -INSERT INTO t1(docid,words) VALUES(1009002,'And the fear of you and the dread of you shall be upon every beast of the earth, and upon every fowl of the air, upon all that moveth upon the earth, and upon all the fishes of the sea; into your hand are they delivered.'); -INSERT INTO t1(docid,words) VALUES(1009003,'Every moving thing that liveth shall be meat for you; even as the green herb have I given you all things.'); -INSERT INTO t1(docid,words) VALUES(1009004,'But flesh with the life thereof, which is the blood thereof, shall ye not eat.'); -INSERT INTO t1(docid,words) VALUES(1009005,'And surely your blood of your lives will I require; at the hand of every beast will I require it, and at the hand of man; at the hand of every man''s brother will I require the life of man.'); -INSERT INTO t1(docid,words) VALUES(1009006,'Whoso sheddeth man''s blood, by man shall his blood be shed: for in the image of God made he man.'); -INSERT INTO t1(docid,words) VALUES(1009007,'And you, be ye fruitful, and multiply; bring forth abundantly in the earth, and multiply therein.'); -INSERT INTO t1(docid,words) VALUES(1009008,'And God spake unto Noah, and to his sons with him, saying,'); -INSERT INTO t1(docid,words) VALUES(1009009,'And I, behold, I establish my covenant with you, and with your seed after you;'); -INSERT INTO t1(docid,words) VALUES(1009010,'And with every living creature that is with you, of the fowl, of the cattle, and of every beast of the earth with you; from all that go out of the ark, to every beast of the earth.'); -INSERT INTO t1(docid,words) VALUES(1009011,'And I will establish my covenant with you, neither shall all flesh be cut off any more by the waters of a flood; neither shall there any more be a flood to destroy the earth.'); -INSERT INTO t1(docid,words) VALUES(1009012,'And God said, This is the token of the covenant which I make between me and you and every living creature that is with you, for perpetual generations:'); -INSERT INTO t1(docid,words) VALUES(1009013,'I do set my bow in the cloud, and it shall be for a token of a covenant between me and the earth.'); -INSERT INTO t1(docid,words) VALUES(1009014,'And it shall come to pass, when I bring a cloud over the earth, that the bow shall be seen in the cloud:'); -INSERT INTO t1(docid,words) VALUES(1009015,'And I will remember my covenant, which is between me and you and every living creature of all flesh; and the waters shall no more become a flood to destroy all flesh.'); -INSERT INTO t1(docid,words) VALUES(1009016,'And the bow shall be in the cloud; and I will look upon it, that I may remember the everlasting covenant between God and every living creature of all flesh that is upon the earth.'); -INSERT INTO t1(docid,words) VALUES(1009017,'And God said unto Noah, This is the token of the covenant, which I have established between me and all flesh that is upon the earth.'); -INSERT INTO t1(docid,words) VALUES(1009018,'And the sons of Noah, that went forth of the ark, were Shem, and Ham, and Japheth: and Ham is the father of Canaan.'); -INSERT INTO t1(docid,words) VALUES(1009019,'These are the three sons of Noah: and of them was the whole earth overspread.'); -INSERT INTO t1(docid,words) VALUES(1009020,'And Noah began to be an husbandman, and he planted a vineyard:'); -INSERT INTO t1(docid,words) VALUES(1009021,'And he drank of the wine, and was drunken; and he was uncovered within his tent.'); -INSERT INTO t1(docid,words) VALUES(1009022,'And Ham, the father of Canaan, saw the nakedness of his father, and told his two brethren without.'); -INSERT INTO t1(docid,words) VALUES(1009023,'And Shem and Japheth took a garment, and laid it upon both their shoulders, and went backward, and covered the nakedness of their father; and their faces were backward, and they saw not their father''s nakedness.'); -INSERT INTO t1(docid,words) VALUES(1009024,'And Noah awoke from his wine, and knew what his younger son had done unto him.'); -INSERT INTO t1(docid,words) VALUES(1009025,'And he said, Cursed be Canaan; a servant of servants shall he be unto his brethren.'); -INSERT INTO t1(docid,words) VALUES(1009026,'And he said, Blessed be the LORD God of Shem; and Canaan shall be his servant.'); -INSERT INTO t1(docid,words) VALUES(1009027,'God shall enlarge Japheth, and he shall dwell in the tents of Shem; and Canaan shall be his servant.'); -INSERT INTO t1(docid,words) VALUES(1009028,'And Noah lived after the flood three hundred and fifty years.'); -INSERT INTO t1(docid,words) VALUES(1009029,'And all the days of Noah were nine hundred and fifty years: and he died.'); -INSERT INTO t1(docid,words) VALUES(1010001,'Now these are the generations of the sons of Noah, Shem, Ham, and Japheth: and unto them were sons born after the flood.'); -INSERT INTO t1(docid,words) VALUES(1010002,'The sons of Japheth; Gomer, and Magog, and Madai, and Javan, and Tubal, and Meshech, and Tiras.'); -INSERT INTO t1(docid,words) VALUES(1010003,'And the sons of Gomer; Ashkenaz, and Riphath, and Togarmah.'); -INSERT INTO t1(docid,words) VALUES(1010004,'And the sons of Javan; Elishah, and Tarshish, Kittim, and Dodanim.'); -INSERT INTO t1(docid,words) VALUES(1010005,'By these were the isles of the Gentiles divided in their lands; every one after his tongue, after their families, in their nations.'); -INSERT INTO t1(docid,words) VALUES(1010006,'And the sons of Ham; Cush, and Mizraim, and Phut, and Canaan.'); -INSERT INTO t1(docid,words) VALUES(1010007,'And the sons of Cush; Seba, and Havilah, and Sabtah, and Raamah, and Sabtechah: and the sons of Raamah; Sheba, and Dedan.'); -INSERT INTO t1(docid,words) VALUES(1010008,'And Cush begat Nimrod: he began to be a mighty one in the earth.'); -INSERT INTO t1(docid,words) VALUES(1010009,'He was a mighty hunter before the LORD: wherefore it is said, Even as Nimrod the mighty hunter before the LORD.'); -INSERT INTO t1(docid,words) VALUES(1010010,'And the beginning of his kingdom was Babel, and Erech, and Accad, and Calneh, in the land of Shinar.'); -INSERT INTO t1(docid,words) VALUES(1010011,'Out of that land went forth Asshur, and builded Nineveh, and the city Rehoboth, and Calah,'); -INSERT INTO t1(docid,words) VALUES(1010012,'And Resen between Nineveh and Calah: the same is a great city.'); -INSERT INTO t1(docid,words) VALUES(1010013,'And Mizraim begat Ludim, and Anamim, and Lehabim, and Naphtuhim,'); -INSERT INTO t1(docid,words) VALUES(1010014,'And Pathrusim, and Casluhim, (out of whom came Philistim,) and Caphtorim.'); -INSERT INTO t1(docid,words) VALUES(1010015,'And Canaan begat Sidon his first born, and Heth,'); -INSERT INTO t1(docid,words) VALUES(1010016,'And the Jebusite, and the Amorite, and the Girgasite,'); -INSERT INTO t1(docid,words) VALUES(1010017,'And the Hivite, and the Arkite, and the Sinite,'); -INSERT INTO t1(docid,words) VALUES(1010018,'And the Arvadite, and the Zemarite, and the Hamathite: and afterward were the families of the Canaanites spread abroad.'); -INSERT INTO t1(docid,words) VALUES(1010019,'And the border of the Canaanites was from Sidon, as thou comest to Gerar, unto Gaza; as thou goest, unto Sodom, and Gomorrah, and Admah, and Zeboim, even unto Lasha.'); -INSERT INTO t1(docid,words) VALUES(1010020,'These are the sons of Ham, after their families, after their tongues, in their countries, and in their nations.'); -INSERT INTO t1(docid,words) VALUES(1010021,'Unto Shem also, the father of all the children of Eber, the brother of Japheth the elder, even to him were children born.'); -INSERT INTO t1(docid,words) VALUES(1010022,'The children of Shem; Elam, and Asshur, and Arphaxad, and Lud, and Aram.'); -INSERT INTO t1(docid,words) VALUES(1010023,'And the children of Aram; Uz, and Hul, and Gether, and Mash.'); -INSERT INTO t1(docid,words) VALUES(1010024,'And Arphaxad begat Salah; and Salah begat Eber.'); -INSERT INTO t1(docid,words) VALUES(1010025,'And unto Eber were born two sons: the name of one was Peleg; for in his days was the earth divided; and his brother''s name was Joktan.'); -INSERT INTO t1(docid,words) VALUES(1010026,'And Joktan begat Almodad, and Sheleph, and Hazarmaveth, and Jerah,'); -INSERT INTO t1(docid,words) VALUES(1010027,'And Hadoram, and Uzal, and Diklah,'); -INSERT INTO t1(docid,words) VALUES(1010028,'And Obal, and Abimael, and Sheba,'); -INSERT INTO t1(docid,words) VALUES(1010029,'And Ophir, and Havilah, and Jobab: all these were the sons of Joktan.'); -INSERT INTO t1(docid,words) VALUES(1010030,'And their dwelling was from Mesha, as thou goest unto Sephar a mount of the east.'); -INSERT INTO t1(docid,words) VALUES(1010031,'These are the sons of Shem, after their families, after their tongues, in their lands, after their nations.'); -INSERT INTO t1(docid,words) VALUES(1010032,'These are the families of the sons of Noah, after their generations, in their nations: and by these were the nations divided in the earth after the flood.'); -INSERT INTO t1(docid,words) VALUES(1011001,'And the whole earth was of one language, and of one speech.'); -INSERT INTO t1(docid,words) VALUES(1011002,'And it came to pass, as they journeyed from the east, that they found a plain in the land of Shinar; and they dwelt there.'); -INSERT INTO t1(docid,words) VALUES(1011003,'And they said one to another, Go to, let us make brick, and burn them thoroughly. And they had brick for stone, and slime had they for morter.'); -INSERT INTO t1(docid,words) VALUES(1011004,'And they said, Go to, let us build us a city and a tower, whose top may reach unto heaven; and let us make us a name, lest we be scattered abroad upon the face of the whole earth.'); -INSERT INTO t1(docid,words) VALUES(1011005,'And the LORD came down to see the city and the tower, which the children of men builded.'); -INSERT INTO t1(docid,words) VALUES(1011006,'And the LORD said, Behold, the people is one, and they have all one language; and this they begin to do: and now nothing will be restrained from them, which they have imagined to do.'); -INSERT INTO t1(docid,words) VALUES(1011007,'Go to, let us go down, and there confound their language, that they may not understand one another''s speech.'); -INSERT INTO t1(docid,words) VALUES(1011008,'So the LORD scattered them abroad from thence upon the face of all the earth: and they left off to build the city.'); -INSERT INTO t1(docid,words) VALUES(1011009,'Therefore is the name of it called Babel; because the LORD did there confound the language of all the earth: and from thence did the LORD scatter them abroad upon the face of all the earth.'); -INSERT INTO t1(docid,words) VALUES(1011010,'These are the generations of Shem: Shem was an hundred years old, and begat Arphaxad two years after the flood:'); -INSERT INTO t1(docid,words) VALUES(1011011,'And Shem lived after he begat Arphaxad five hundred years, and begat sons and daughters.'); -INSERT INTO t1(docid,words) VALUES(1011012,'And Arphaxad lived five and thirty years, and begat Salah:'); -INSERT INTO t1(docid,words) VALUES(1011013,'And Arphaxad lived after he begat Salah four hundred and three years, and begat sons and daughters.'); -INSERT INTO t1(docid,words) VALUES(1011014,'And Salah lived thirty years, and begat Eber:'); -INSERT INTO t1(docid,words) VALUES(1011015,'And Salah lived after he begat Eber four hundred and three years, and begat sons and daughters.'); -INSERT INTO t1(docid,words) VALUES(1011016,'And Eber lived four and thirty years, and begat Peleg:'); -INSERT INTO t1(docid,words) VALUES(1011017,'And Eber lived after he begat Peleg four hundred and thirty years, and begat sons and daughters.'); -INSERT INTO t1(docid,words) VALUES(1011018,'And Peleg lived thirty years, and begat Reu:'); -INSERT INTO t1(docid,words) VALUES(1011019,'And Peleg lived after he begat Reu two hundred and nine years, and begat sons and daughters.'); -INSERT INTO t1(docid,words) VALUES(1011020,'And Reu lived two and thirty years, and begat Serug:'); -INSERT INTO t1(docid,words) VALUES(1011021,'And Reu lived after he begat Serug two hundred and seven years, and begat sons and daughters.'); -INSERT INTO t1(docid,words) VALUES(1011022,'And Serug lived thirty years, and begat Nahor:'); -INSERT INTO t1(docid,words) VALUES(1011023,'And Serug lived after he begat Nahor two hundred years, and begat sons and daughters.'); -INSERT INTO t1(docid,words) VALUES(1011024,'And Nahor lived nine and twenty years, and begat Terah:'); -INSERT INTO t1(docid,words) VALUES(1011025,'And Nahor lived after he begat Terah an hundred and nineteen years, and begat sons and daughters.'); -INSERT INTO t1(docid,words) VALUES(1011026,'And Terah lived seventy years, and begat Abram, Nahor, and Haran.'); -INSERT INTO t1(docid,words) VALUES(1011027,'Now these are the generations of Terah: Terah begat Abram, Nahor, and Haran; and Haran begat Lot.'); -INSERT INTO t1(docid,words) VALUES(1011028,'And Haran died before his father Terah in the land of his nativity, in Ur of the Chaldees.'); -INSERT INTO t1(docid,words) VALUES(1011029,'And Abram and Nahor took them wives: the name of Abram''s wife was Sarai; and the name of Nahor''s wife, Milcah, the daughter of Haran, the father of Milcah, and the father of Iscah.'); -INSERT INTO t1(docid,words) VALUES(1011030,'But Sarai was barren; she had no child.'); -INSERT INTO t1(docid,words) VALUES(1011031,'And Terah took Abram his son, and Lot the son of Haran his son''s son, and Sarai his daughter in law, his son Abram''s wife; and they went forth with them from Ur of the Chaldees, to go into the land of Canaan; and they came unto Haran, and dwelt there.'); -INSERT INTO t1(docid,words) VALUES(1011032,'And the days of Terah were two hundred and five years: and Terah died in Haran.'); -INSERT INTO t1(docid,words) VALUES(1012001,'Now the LORD had said unto Abram, Get thee out of thy country, and from thy kindred, and from thy father''s house, unto a land that I will shew thee:'); -INSERT INTO t1(docid,words) VALUES(1012002,'And I will make of thee a great nation, and I will bless thee, and make thy name great; and thou shalt be a blessing:'); -INSERT INTO t1(docid,words) VALUES(1012003,'And I will bless them that bless thee, and curse him that curseth thee: and in thee shall all families of the earth be blessed.'); -INSERT INTO t1(docid,words) VALUES(1012004,'So Abram departed, as the LORD had spoken unto him; and Lot went with him: and Abram was seventy and five years old when he departed out of Haran.'); -INSERT INTO t1(docid,words) VALUES(1012005,'And Abram took Sarai his wife, and Lot his brother''s son, and all their substance that they had gathered, and the souls that they had gotten in Haran; and they went forth to go into the land of Canaan; and into the land of Canaan they came.'); -INSERT INTO t1(docid,words) VALUES(1012006,'And Abram passed through the land unto the place of Sichem, unto the plain of Moreh. And the Canaanite was then in the land.'); -INSERT INTO t1(docid,words) VALUES(1012007,'And the LORD appeared unto Abram, and said, Unto thy seed will I give this land: and there builded he an altar unto the LORD, who appeared unto him.'); -INSERT INTO t1(docid,words) VALUES(1012008,'And he removed from thence unto a mountain on the east of Bethel, and pitched his tent, having Bethel on the west, and Hai on the east: and there he builded an altar unto the LORD, and called upon the name of the LORD.'); -INSERT INTO t1(docid,words) VALUES(1012009,'And Abram journeyed, going on still toward the south.'); -INSERT INTO t1(docid,words) VALUES(1012010,'And there was a famine in the land: and Abram went down into Egypt to sojourn there; for the famine was grievous in the land.'); -INSERT INTO t1(docid,words) VALUES(1012011,'And it came to pass, when he was come near to enter into Egypt, that he said unto Sarai his wife, Behold now, I know that thou art a fair woman to look upon:'); -INSERT INTO t1(docid,words) VALUES(1012012,'Therefore it shall come to pass, when the Egyptians shall see thee, that they shall say, This is his wife: and they will kill me, but they will save thee alive.'); -INSERT INTO t1(docid,words) VALUES(1012013,'Say, I pray thee, thou art my sister: that it may be well with me for thy sake; and my soul shall live because of thee.'); -INSERT INTO t1(docid,words) VALUES(1012014,'And it came to pass, that, when Abram was come into Egypt, the Egyptians beheld the woman that she was very fair.'); -INSERT INTO t1(docid,words) VALUES(1012015,'The princes also of Pharaoh saw her, and commended her before Pharaoh: and the woman was taken into Pharaoh''s house.'); -INSERT INTO t1(docid,words) VALUES(1012016,'And he entreated Abram well for her sake: and he had sheep, and oxen, and he asses, and menservants, and maidservants, and she asses, and camels.'); -INSERT INTO t1(docid,words) VALUES(1012017,'And the LORD plagued Pharaoh and his house with great plagues because of Sarai Abram''s wife.'); -INSERT INTO t1(docid,words) VALUES(1012018,'And Pharaoh called Abram and said, What is this that thou hast done unto me? why didst thou not tell me that she was thy wife?'); -INSERT INTO t1(docid,words) VALUES(1012019,'Why saidst thou, She is my sister? so I might have taken her to me to wife: now therefore behold thy wife, take her, and go thy way.'); -INSERT INTO t1(docid,words) VALUES(1012020,'And Pharaoh commanded his men concerning him: and they sent him away, and his wife, and all that he had.'); -INSERT INTO t1(docid,words) VALUES(1013001,'And Abram went up out of Egypt, he, and his wife, and all that he had, and Lot with him, into the south.'); -INSERT INTO t1(docid,words) VALUES(1013002,'And Abram was very rich in cattle, in silver, and in gold.'); -INSERT INTO t1(docid,words) VALUES(1013003,'And he went on his journeys from the south even to Bethel, unto the place where his tent had been at the beginning, between Bethel and Hai;'); -INSERT INTO t1(docid,words) VALUES(1013004,'Unto the place of the altar, which he had make there at the first: and there Abram called on the name of the LORD.'); -INSERT INTO t1(docid,words) VALUES(1013005,'And Lot also, which went with Abram, had flocks, and herds, and tents.'); -INSERT INTO t1(docid,words) VALUES(1013006,'And the land was not able to bear them, that they might dwell together: for their substance was great, so that they could not dwell together.'); -INSERT INTO t1(docid,words) VALUES(1013007,'And there was a strife between the herdmen of Abram''s cattle and the herdmen of Lot''s cattle: and the Canaanite and the Perizzite dwelled then in the land.'); -INSERT INTO t1(docid,words) VALUES(1013008,'And Abram said unto Lot, Let there be no strife, I pray thee, between me and thee, and between my herdmen and thy herdmen; for we be brethren.'); -INSERT INTO t1(docid,words) VALUES(1013009,'Is not the whole land before thee? separate thyself, I pray thee, from me: if thou wilt take the left hand, then I will go to the right; or if thou depart to the right hand, then I will go to the left.'); -INSERT INTO t1(docid,words) VALUES(1013010,'And Lot lifted up his eyes, and beheld all the plain of Jordan, that it was well watered every where, before the LORD destroyed Sodom and Gomorrah, even as the garden of the LORD, like the land of Egypt, as thou comest unto Zoar.'); -INSERT INTO t1(docid,words) VALUES(1013011,'Then Lot chose him all the plain of Jordan; and Lot journeyed east: and they separated themselves the one from the other.'); -INSERT INTO t1(docid,words) VALUES(1013012,'Abram dwelled in the land of Canaan, and Lot dwelled in the cities of the plain, and pitched his tent toward Sodom.'); -INSERT INTO t1(docid,words) VALUES(1013013,'But the men of Sodom were wicked and sinners before the LORD exceedingly.'); -INSERT INTO t1(docid,words) VALUES(1013014,'And the LORD said unto Abram, after that Lot was separated from him, Lift up now thine eyes, and look from the place where thou art northward, and southward, and eastward, and westward:'); -INSERT INTO t1(docid,words) VALUES(1013015,'For all the land which thou seest, to thee will I give it, and to thy seed for ever.'); -INSERT INTO t1(docid,words) VALUES(1013016,'And I will make thy seed as the dust of the earth: so that if a man can number the dust of the earth, then shall thy seed also be numbered.'); -INSERT INTO t1(docid,words) VALUES(1013017,'Arise, walk through the land in the length of it and in the breadth of it; for I will give it unto thee.'); -INSERT INTO t1(docid,words) VALUES(1013018,'Then Abram removed his tent, and came and dwelt in the plain of Mamre, which is in Hebron, and built there an altar unto the LORD.'); -INSERT INTO t1(docid,words) VALUES(1014001,'And it came to pass in the days of Amraphel king of Shinar, Arioch king of Ellasar, Chedorlaomer king of Elam, and Tidal king of nations;'); -INSERT INTO t1(docid,words) VALUES(1014002,'That these made war with Bera king of Sodom, and with Birsha king of Gomorrah, Shinab king of Admah, and Shemeber king of Zeboiim, and the king of Bela, which is Zoar.'); -INSERT INTO t1(docid,words) VALUES(1014003,'All these were joined together in the vale of Siddim, which is the salt sea.'); -INSERT INTO t1(docid,words) VALUES(1014004,'Twelve years they served Chedorlaomer, and in the thirteenth year they rebelled.'); -INSERT INTO t1(docid,words) VALUES(1014005,'And in the fourteenth year came Chedorlaomer, and the kings that were with him, and smote the Rephaims in Ashteroth Karnaim, and the Zuzims in Ham, and the Emins in Shaveh Kiriathaim,'); -INSERT INTO t1(docid,words) VALUES(1014006,'And the Horites in their mount Seir, unto Elparan, which is by the wilderness.'); -INSERT INTO t1(docid,words) VALUES(1014007,'And they returned, and came to Enmishpat, which is Kadesh, and smote all the country of the Amalekites, and also the Amorites, that dwelt in Hazezontamar.'); -INSERT INTO t1(docid,words) VALUES(1014008,'And there went out the king of Sodom, and the king of Gomorrah, and the king of Admah, and the king of Zeboiim, and the king of Bela (the same is Zoar;) and they joined battle with them in the vale of Siddim;'); -INSERT INTO t1(docid,words) VALUES(1014009,'With Chedorlaomer the king of Elam, and with Tidal king of nations, and Amraphel king of Shinar, and Arioch king of Ellasar; four kings with five.'); -INSERT INTO t1(docid,words) VALUES(1014010,'And the vale of Siddim was full of slimepits; and the kings of Sodom and Gomorrah fled, and fell there; and they that remained fled to the mountain.'); -INSERT INTO t1(docid,words) VALUES(1014011,'And they took all the goods of Sodom and Gomorrah, and all their victuals, and went their way.'); -INSERT INTO t1(docid,words) VALUES(1014012,'And they took Lot, Abram''s brother''s son, who dwelt in Sodom, and his goods, and departed.'); -INSERT INTO t1(docid,words) VALUES(1014013,'And there came one that had escaped, and told Abram the Hebrew; for he dwelt in the plain of Mamre the Amorite, brother of Eshcol, and brother of Aner: and these were confederate with Abram.'); -INSERT INTO t1(docid,words) VALUES(1014014,'And when Abram heard that his brother was taken captive, he armed his trained servants, born in his own house, three hundred and eighteen, and pursued them unto Dan.'); -INSERT INTO t1(docid,words) VALUES(1014015,'And he divided himself against them, he and his servants, by night, and smote them, and pursued them unto Hobah, which is on the left hand of Damascus.'); -INSERT INTO t1(docid,words) VALUES(1014016,'And he brought back all the goods, and also brought again his brother Lot, and his goods, and the women also, and the people.'); -INSERT INTO t1(docid,words) VALUES(1014017,'And the king of Sodom went out to meet him after his return from the slaughter of Chedorlaomer, and of the kings that were with him, at the valley of Shaveh, which is the king''s dale.'); -INSERT INTO t1(docid,words) VALUES(1014018,'And Melchizedek king of Salem brought forth bread and wine: and he was the priest of the most high God.'); -INSERT INTO t1(docid,words) VALUES(1014019,'And he blessed him, and said, Blessed be Abram of the most high God, possessor of heaven and earth:'); -INSERT INTO t1(docid,words) VALUES(1014020,'And blessed be the most high God, which hath delivered thine enemies into thy hand. And he gave him tithes of all.'); -INSERT INTO t1(docid,words) VALUES(1014021,'And the king of Sodom said unto Abram, Give me the persons, and take the goods to thyself.'); -INSERT INTO t1(docid,words) VALUES(1014022,'And Abram said to the king of Sodom, I have lift up mine hand unto the LORD, the most high God, the possessor of heaven and earth,'); -INSERT INTO t1(docid,words) VALUES(1014023,'That I will not take from a thread even to a shoelatchet, and that I will not take any thing that is thine, lest thou shouldest say, I have made Abram rich:'); -INSERT INTO t1(docid,words) VALUES(1014024,'Save only that which the young men have eaten, and the portion of the men which went with me, Aner, Eshcol, and Mamre; let them take their portion.'); -INSERT INTO t1(docid,words) VALUES(1015001,'After these things the word of the LORD came unto Abram in a vision, saying, Fear not, Abram: I am thy shield, and thy exceeding great reward.'); -INSERT INTO t1(docid,words) VALUES(1015002,'And Abram said, LORD God, what wilt thou give me, seeing I go childless, and the steward of my house is this Eliezer of Damascus?'); -INSERT INTO t1(docid,words) VALUES(1015003,'And Abram said, Behold, to me thou hast given no seed: and, lo, one born in my house is mine heir.'); -INSERT INTO t1(docid,words) VALUES(1015004,'And, behold, the word of the LORD came unto him, saying, This shall not be thine heir; but he that shall come forth out of thine own bowels shall be thine heir.'); -INSERT INTO t1(docid,words) VALUES(1015005,'And he brought him forth abroad, and said, Look now toward heaven, and tell the stars, if thou be able to number them: and he said unto him, So shall thy seed be.'); -INSERT INTO t1(docid,words) VALUES(1015006,'And he believed in the LORD; and he counted it to him for righteousness.'); -INSERT INTO t1(docid,words) VALUES(1015007,'And he said unto him, I am the LORD that brought thee out of Ur of the Chaldees, to give thee this land to inherit it.'); -INSERT INTO t1(docid,words) VALUES(1015008,'And he said, LORD God, whereby shall I know that I shall inherit it?'); -INSERT INTO t1(docid,words) VALUES(1015009,'And he said unto him, Take me an heifer of three years old, and a she goat of three years old, and a ram of three years old, and a turtledove, and a young pigeon.'); -INSERT INTO t1(docid,words) VALUES(1015010,'And he took unto him all these, and divided them in the midst, and laid each piece one against another: but the birds divided he not.'); -INSERT INTO t1(docid,words) VALUES(1015011,'And when the fowls came down upon the carcases, Abram drove them away.'); -INSERT INTO t1(docid,words) VALUES(1015012,'And when the sun was going down, a deep sleep fell upon Abram; and, lo, an horror of great darkness fell upon him.'); -INSERT INTO t1(docid,words) VALUES(1015013,'And he said unto Abram, Know of a surety that thy seed shall be a stranger in a land that is not their''s, and shall serve them; and they shall afflict them four hundred years;'); -INSERT INTO t1(docid,words) VALUES(1015014,'And also that nation, whom they shall serve, will I judge: and afterward shall they come out with great substance.'); -INSERT INTO t1(docid,words) VALUES(1015015,'And thou shalt go to thy fathers in peace; thou shalt be buried in a good old age.'); -INSERT INTO t1(docid,words) VALUES(1015016,'But in the fourth generation they shall come hither again: for the iniquity of the Amorites is not yet full.'); -INSERT INTO t1(docid,words) VALUES(1015017,'And it came to pass, that, when the sun went down, and it was dark, behold a smoking furnace, and a burning lamp that passed between those pieces.'); -INSERT INTO t1(docid,words) VALUES(1015018,'In the same day the LORD made a covenant with Abram, saying, Unto thy seed have I given this land, from the river of Egypt unto the great river, the river Euphrates:'); -INSERT INTO t1(docid,words) VALUES(1015019,'The Kenites, and the Kenizzites, and the Kadmonites,'); -INSERT INTO t1(docid,words) VALUES(1015020,'And the Hittites, and the Perizzites, and the Rephaims,'); -INSERT INTO t1(docid,words) VALUES(1015021,'And the Amorites, and the Canaanites, and the Girgashites, and the Jebusites.'); -INSERT INTO t1(docid,words) VALUES(1016001,'Now Sarai Abram''s wife bare him no children: and she had an handmaid, an Egyptian, whose name was Hagar.'); -INSERT INTO t1(docid,words) VALUES(1016002,'And Sarai said unto Abram, Behold now, the LORD hath restrained me from bearing: I pray thee, go in unto my maid; it may be that I may obtain children by her. And Abram hearkened to the voice of Sarai.'); -INSERT INTO t1(docid,words) VALUES(1016003,'And Sarai Abram''s wife took Hagar her maid the Egyptian, after Abram had dwelt ten years in the land of Canaan, and gave her to her husband Abram to be his wife.'); -INSERT INTO t1(docid,words) VALUES(1016004,'And he went in unto Hagar, and she conceived: and when she saw that she had conceived, her mistress was despised in her eyes.'); -INSERT INTO t1(docid,words) VALUES(1016005,'And Sarai said unto Abram, My wrong be upon thee: I have given my maid into thy bosom; and when she saw that she had conceived, I was despised in her eyes: the LORD judge between me and thee.'); -INSERT INTO t1(docid,words) VALUES(1016006,'But Abram said unto Sarai, Behold, thy maid is in thine hand; do to her as it pleaseth thee. And when Sarai dealt hardly with her, she fled from her face.'); -INSERT INTO t1(docid,words) VALUES(1016007,'And the angel of the LORD found her by a fountain of water in the wilderness, by the fountain in the way to Shur.'); -INSERT INTO t1(docid,words) VALUES(1016008,'And he said, Hagar, Sarai''s maid, whence camest thou? and whither wilt thou go? And she said, I flee from the face of my mistress Sarai.'); -INSERT INTO t1(docid,words) VALUES(1016009,'And the angel of the LORD said unto her, Return to thy mistress, and submit thyself under her hands.'); -INSERT INTO t1(docid,words) VALUES(1016010,'And the angel of the LORD said unto her, I will multiply thy seed exceedingly, that it shall not be numbered for multitude.'); -INSERT INTO t1(docid,words) VALUES(1016011,'And the angel of the LORD said unto her, Behold, thou art with child and shalt bear a son, and shalt call his name Ishmael; because the LORD hath heard thy affliction.'); -INSERT INTO t1(docid,words) VALUES(1016012,'And he will be a wild man; his hand will be against every man, and every man''s hand against him; and he shall dwell in the presence of all his brethren.'); -INSERT INTO t1(docid,words) VALUES(1016013,'And she called the name of the LORD that spake unto her, Thou God seest me: for she said, Have I also here looked after him that seeth me?'); -INSERT INTO t1(docid,words) VALUES(1016014,'Wherefore the well was called Beerlahairoi; behold, it is between Kadesh and Bered.'); -INSERT INTO t1(docid,words) VALUES(1016015,'And Hagar bare Abram a son: and Abram called his son''s name, which Hagar bare, Ishmael.'); -INSERT INTO t1(docid,words) VALUES(1016016,'And Abram was fourscore and six years old, when Hagar bare Ishmael to Abram.'); -INSERT INTO t1(docid,words) VALUES(1017001,'And when Abram was ninety years old and nine, the LORD appeared to Abram, and said unto him, I am the Almighty God; walk before me, and be thou perfect.'); -INSERT INTO t1(docid,words) VALUES(1017002,'And I will make my covenant between me and thee, and will multiply thee exceedingly.'); -INSERT INTO t1(docid,words) VALUES(1017003,'And Abram fell on his face: and God talked with him, saying,'); -INSERT INTO t1(docid,words) VALUES(1017004,'As for me, behold, my covenant is with thee, and thou shalt be a father of many nations.'); -INSERT INTO t1(docid,words) VALUES(1017005,'Neither shall thy name any more be called Abram, but thy name shall be Abraham; for a father of many nations have I made thee.'); -INSERT INTO t1(docid,words) VALUES(1017006,'And I will make thee exceeding fruitful, and I will make nations of thee, and kings shall come out of thee.'); -INSERT INTO t1(docid,words) VALUES(1017007,'And I will establish my covenant between me and thee and thy seed after thee in their generations for an everlasting covenant, to be a God unto thee, and to thy seed after thee.'); -INSERT INTO t1(docid,words) VALUES(1017008,'And I will give unto thee, and to thy seed after thee, the land wherein thou art a stranger, all the land of Canaan, for an everlasting possession; and I will be their God.'); -INSERT INTO t1(docid,words) VALUES(1017009,'And God said unto Abraham, Thou shalt keep my covenant therefore, thou, and thy seed after thee in their generations.'); -INSERT INTO t1(docid,words) VALUES(1017010,'This is my covenant, which ye shall keep, between me and you and thy seed after thee; Every man child among you shall be circumcised.'); -INSERT INTO t1(docid,words) VALUES(1017011,'And ye shall circumcise the flesh of your foreskin; and it shall be a token of the covenant betwixt me and you.'); -INSERT INTO t1(docid,words) VALUES(1017012,'And he that is eight days old shall be circumcised among you, every man child in your generations, he that is born in the house, or bought with money of any stranger, which is not of thy seed.'); -INSERT INTO t1(docid,words) VALUES(1017013,'He that is born in thy house, and he that is bought with thy money, must needs be circumcised: and my covenant shall be in your flesh for an everlasting covenant.'); -INSERT INTO t1(docid,words) VALUES(1017014,'And the uncircumcised man child whose flesh of his foreskin is not circumcised, that soul shall be cut off from his people; he hath broken my covenant.'); -INSERT INTO t1(docid,words) VALUES(1017015,'And God said unto Abraham, As for Sarai thy wife, thou shalt not call her name Sarai, but Sarah shall her name be.'); -INSERT INTO t1(docid,words) VALUES(1017016,'And I will bless her, and give thee a son also of her: yea, I will bless her, and she shall be a mother of nations; kings of people shall be of her.'); -INSERT INTO t1(docid,words) VALUES(1017017,'Then Abraham fell upon his face, and laughed, and said in his heart, Shall a child be born unto him that is an hundred years old? and shall Sarah, that is ninety years old, bear?'); -INSERT INTO t1(docid,words) VALUES(1017018,'And Abraham said unto God, O that Ishmael might live before thee!'); -INSERT INTO t1(docid,words) VALUES(1017019,'And God said, Sarah thy wife shall bear thee a son indeed; and thou shalt call his name Isaac: and I will establish my covenant with him for an everlasting covenant, and with his seed after him.'); -INSERT INTO t1(docid,words) VALUES(1017020,'And as for Ishmael, I have heard thee: Behold, I have blessed him, and will make him fruitful, and will multiply him exceedingly; twelve princes shall he beget, and I will make him a great nation.'); -INSERT INTO t1(docid,words) VALUES(1017021,'But my covenant will I establish with Isaac, which Sarah shall bear unto thee at this set time in the next year.'); -INSERT INTO t1(docid,words) VALUES(1017022,'And he left off talking with him, and God went up from Abraham.'); -INSERT INTO t1(docid,words) VALUES(1017023,'And Abraham took Ishmael his son, and all that were born in his house, and all that were bought with his money, every male among the men of Abraham''s house; and circumcised the flesh of their foreskin in the selfsame day, as God had said unto him.'); -INSERT INTO t1(docid,words) VALUES(1017024,'And Abraham was ninety years old and nine, when he was circumcised in the flesh of his foreskin.'); -INSERT INTO t1(docid,words) VALUES(1017025,'And Ishmael his son was thirteen years old, when he was circumcised in the flesh of his foreskin.'); -INSERT INTO t1(docid,words) VALUES(1017026,'In the selfsame day was Abraham circumcised, and Ishmael his son.'); -INSERT INTO t1(docid,words) VALUES(1017027,'And all the men of his house, born in the house, and bought with money of the stranger, were circumcised with him.'); -INSERT INTO t1(docid,words) VALUES(1018001,'And the LORD appeared unto him in the plains of Mamre: and he sat in the tent door in the heat of the day;'); -INSERT INTO t1(docid,words) VALUES(1018002,'And he lift up his eyes and looked, and, lo, three men stood by him: and when he saw them, he ran to meet them from the tent door, and bowed himself toward the ground,'); -INSERT INTO t1(docid,words) VALUES(1018003,'And said, My LORD, if now I have found favour in thy sight, pass not away, I pray thee, from thy servant:'); -INSERT INTO t1(docid,words) VALUES(1018004,'Let a little water, I pray you, be fetched, and wash your feet, and rest yourselves under the tree:'); -INSERT INTO t1(docid,words) VALUES(1018005,'And I will fetch a morsel of bread, and comfort ye your hearts; after that ye shall pass on: for therefore are ye come to your servant. And they said, So do, as thou hast said.'); -INSERT INTO t1(docid,words) VALUES(1018006,'And Abraham hastened into the tent unto Sarah, and said, Make ready quickly three measures of fine meal, knead it, and make cakes upon the hearth.'); -INSERT INTO t1(docid,words) VALUES(1018007,'And Abraham ran unto the herd, and fetcht a calf tender and good, and gave it unto a young man; and he hasted to dress it.'); -INSERT INTO t1(docid,words) VALUES(1018008,'And he took butter, and milk, and the calf which he had dressed, and set it before them; and he stood by them under the tree, and they did eat.'); -INSERT INTO t1(docid,words) VALUES(1018009,'And they said unto him, Where is Sarah thy wife? And he said, Behold, in the tent.'); -INSERT INTO t1(docid,words) VALUES(1018010,'And he said, I will certainly return unto thee according to the time of life; and, lo, Sarah thy wife shall have a son. And Sarah heard it in the tent door, which was behind him.'); -INSERT INTO t1(docid,words) VALUES(1018011,'Now Abraham and Sarah were old and well stricken in age; and it ceased to be with Sarah after the manner of women.'); -INSERT INTO t1(docid,words) VALUES(1018012,'Therefore Sarah laughed within herself, saying, After I am waxed old shall I have pleasure, my lord being old also?'); -INSERT INTO t1(docid,words) VALUES(1018013,'And the LORD said unto Abraham, Wherefore did Sarah laugh, saying, Shall I of a surety bear a child, which am old?'); -INSERT INTO t1(docid,words) VALUES(1018014,'Is any thing too hard for the LORD? At the time appointed I will return unto thee, according to the time of life, and Sarah shall have a son.'); -INSERT INTO t1(docid,words) VALUES(1018015,'Then Sarah denied, saying, I laughed not; for she was afraid. And he said, Nay; but thou didst laugh.'); -INSERT INTO t1(docid,words) VALUES(1018016,'And the men rose up from thence, and looked toward Sodom: and Abraham went with them to bring them on the way.'); -INSERT INTO t1(docid,words) VALUES(1018017,'And the LORD said, Shall I hide from Abraham that thing which I do;'); -INSERT INTO t1(docid,words) VALUES(1018018,'Seeing that Abraham shall surely become a great and mighty nation, and all the nations of the earth shall be blessed in him?'); -INSERT INTO t1(docid,words) VALUES(1018019,'For I know him, that he will command his children and his household after him, and they shall keep the way of the LORD, to do justice and judgment; that the LORD may bring upon Abraham that which he hath spoken of him.'); -INSERT INTO t1(docid,words) VALUES(1018020,'And the LORD said, Because the cry of Sodom and Gomorrah is great, and because their sin is very grievous;'); -INSERT INTO t1(docid,words) VALUES(1018021,'I will go down now, and see whether they have done altogether according to the cry of it, which is come unto me; and if not, I will know.'); -INSERT INTO t1(docid,words) VALUES(1018022,'And the men turned their faces from thence, and went toward Sodom: but Abraham stood yet before the LORD.'); -INSERT INTO t1(docid,words) VALUES(1018023,'And Abraham drew near, and said, Wilt thou also destroy the righteous with the wicked?'); -INSERT INTO t1(docid,words) VALUES(1018024,'Peradventure there be fifty righteous within the city: wilt thou also destroy and not spare the place for the fifty righteous that are therein?'); -INSERT INTO t1(docid,words) VALUES(1018025,'That be far from thee to do after this manner, to slay the righteous with the wicked: and that the righteous should be as the wicked, that be far from thee: Shall not the Judge of all the earth do right?'); -INSERT INTO t1(docid,words) VALUES(1018026,'And the LORD said, If I find in Sodom fifty righteous within the city, then I will spare all the place for their sakes.'); -INSERT INTO t1(docid,words) VALUES(1018027,'And Abraham answered and said, Behold now, I have taken upon me to speak unto the LORD, which am but dust and ashes:'); -INSERT INTO t1(docid,words) VALUES(1018028,'Peradventure there shall lack five of the fifty righteous: wilt thou destroy all the city for lack of five? And he said, If I find there forty and five, I will not destroy it.'); -INSERT INTO t1(docid,words) VALUES(1018029,'And he spake unto him yet again, and said, Peradventure there shall be forty found there. And he said, I will not do it for forty''s sake.'); -INSERT INTO t1(docid,words) VALUES(1018030,'And he said unto him, Oh let not the LORD be angry, and I will speak: Peradventure there shall thirty be found there. And he said, I will not do it, if I find thirty there.'); -INSERT INTO t1(docid,words) VALUES(1018031,'And he said, Behold now, I have taken upon me to speak unto the LORD: Peradventure there shall be twenty found there. And he said, I will not destroy it for twenty''s sake.'); -INSERT INTO t1(docid,words) VALUES(1018032,'And he said, Oh let not the LORD be angry, and I will speak yet but this once: Peradventure ten shall be found there. And he said, I will not destroy it for ten''s sake.'); -INSERT INTO t1(docid,words) VALUES(1018033,'And the LORD went his way, as soon as he had left communing with Abraham: and Abraham returned unto his place.'); -INSERT INTO t1(docid,words) VALUES(1019001,'And there came two angels to Sodom at even; and Lot sat in the gate of Sodom: and Lot seeing them rose up to meet them; and he bowed himself with his face toward the ground;'); -INSERT INTO t1(docid,words) VALUES(1019002,'And he said, Behold now, my lords, turn in, I pray you, into your servant''s house, and tarry all night, and wash your feet, and ye shall rise up early, and go on your ways. And they said, Nay; but we will abide in the street all night.'); -INSERT INTO t1(docid,words) VALUES(1019003,'And he pressed upon them greatly; and they turned in unto him, and entered into his house; and he made them a feast, and did bake unleavened bread, and they did eat.'); -INSERT INTO t1(docid,words) VALUES(1019004,'But before they lay down, the men of the city, even the men of Sodom, compassed the house round, both old and young, all the people from every quarter:'); -INSERT INTO t1(docid,words) VALUES(1019005,'And they called unto Lot, and said unto him, Where are the men which came in to thee this night? bring them out unto us, that we may know them.'); -INSERT INTO t1(docid,words) VALUES(1019006,'And Lot went out at the door unto them, and shut the door after him,'); -INSERT INTO t1(docid,words) VALUES(1019007,'And said, I pray you, brethren, do not so wickedly.'); -INSERT INTO t1(docid,words) VALUES(1019008,'Behold now, I have two daughters which have not known man; let me, I pray you, bring them out unto you, and do ye to them as is good in your eyes: only unto these men do nothing; for therefore came they under the shadow of my roof.'); -INSERT INTO t1(docid,words) VALUES(1019009,'And they said, Stand back. And they said again, This one fellow came in to sojourn, and he will needs be a judge: now will we deal worse with thee, than with them. And they pressed sore upon the man, even Lot, and came near to break the door.'); -INSERT INTO t1(docid,words) VALUES(1019010,'But the men put forth their hand, and pulled Lot into the house to them, and shut to the door.'); -INSERT INTO t1(docid,words) VALUES(1019011,'And they smote the men that were at the door of the house with blindness, both small and great: so that they wearied themselves to find the door.'); -INSERT INTO t1(docid,words) VALUES(1019012,'And the men said unto Lot, Hast thou here any besides? son in law, and thy sons, and thy daughters, and whatsoever thou hast in the city, bring them out of this place:'); -INSERT INTO t1(docid,words) VALUES(1019013,'For we will destroy this place, because the cry of them is waxen great before the face of the LORD; and the LORD hath sent us to destroy it.'); -INSERT INTO t1(docid,words) VALUES(1019014,'And Lot went out, and spake unto his sons in law, which married his daughters, and said, Up, get you out of this place; for the LORD will destroy this city. But he seemed as one that mocked unto his sons in law.'); -INSERT INTO t1(docid,words) VALUES(1019015,'And when the morning arose, then the angels hastened Lot, saying, Arise, take thy wife, and thy two daughters, which are here; lest thou be consumed in the iniquity of the city.'); -INSERT INTO t1(docid,words) VALUES(1019016,'And while he lingered, the men laid hold upon his hand, and upon the hand of his wife, and upon the hand of his two daughters; the LORD being merciful unto him: and they brought him forth, and set him without the city.'); -INSERT INTO t1(docid,words) VALUES(1019017,'And it came to pass, when they had brought them forth abroad, that he said, Escape for thy life; look not behind thee, neither stay thou in all the plain; escape to the mountain, lest thou be consumed.'); -INSERT INTO t1(docid,words) VALUES(1019018,'And Lot said unto them, Oh, not so, my LORD:'); -INSERT INTO t1(docid,words) VALUES(1019019,'Behold now, thy servant hath found grace in thy sight, and thou hast magnified thy mercy, which thou hast shewed unto me in saving my life; and I cannot escape to the mountain, lest some evil take me, and I die:'); -INSERT INTO t1(docid,words) VALUES(1019020,'Behold now, this city is near to flee unto, and it is a little one: Oh, let me escape thither, (is it not a little one?) and my soul shall live.'); -INSERT INTO t1(docid,words) VALUES(1019021,'And he said unto him, See, I have accepted thee concerning this thing also, that I will not overthrow this city, for the which thou hast spoken.'); -INSERT INTO t1(docid,words) VALUES(1019022,'Haste thee, escape thither; for I cannot do anything till thou be come thither. Therefore the name of the city was called Zoar.'); -INSERT INTO t1(docid,words) VALUES(1019023,'The sun was risen upon the earth when Lot entered into Zoar.'); -INSERT INTO t1(docid,words) VALUES(1019024,'Then the LORD rained upon Sodom and upon Gomorrah brimstone and fire from the LORD out of heaven;'); -INSERT INTO t1(docid,words) VALUES(1019025,'And he overthrew those cities, and all the plain, and all the inhabitants of the cities, and that which grew upon the ground.'); -INSERT INTO t1(docid,words) VALUES(1019026,'But his wife looked back from behind him, and she became a pillar of salt.'); -INSERT INTO t1(docid,words) VALUES(1019027,'And Abraham gat up early in the morning to the place where he stood before the LORD:'); -INSERT INTO t1(docid,words) VALUES(1019028,'And he looked toward Sodom and Gomorrah, and toward all the land of the plain, and beheld, and, lo, the smoke of the country went up as the smoke of a furnace.'); -INSERT INTO t1(docid,words) VALUES(1019029,'And it came to pass, when God destroyed the cities of the plain, that God remembered Abraham, and sent Lot out of the midst of the overthrow, when he overthrew the cities in the which Lot dwelt.'); -INSERT INTO t1(docid,words) VALUES(1019030,'And Lot went up out of Zoar, and dwelt in the mountain, and his two daughters with him; for he feared to dwell in Zoar: and he dwelt in a cave, he and his two daughters.'); -INSERT INTO t1(docid,words) VALUES(1019031,'And the firstborn said unto the younger, Our father is old, and there is not a man in the earth to come in unto us after the manner of all the earth:'); -INSERT INTO t1(docid,words) VALUES(1019032,'Come, let us make our father drink wine, and we will lie with him, that we may preserve seed of our father.'); -INSERT INTO t1(docid,words) VALUES(1019033,'And they made their father drink wine that night: and the firstborn went in, and lay with her father; and he perceived not when she lay down, nor when she arose.'); -INSERT INTO t1(docid,words) VALUES(1019034,'And it came to pass on the morrow, that the firstborn said unto the younger, Behold, I lay yesternight with my father: let us make him drink wine this night also; and go thou in, and lie with him, that we may preserve seed of our father.'); -INSERT INTO t1(docid,words) VALUES(1019035,'And they made their father drink wine that night also: and the younger arose, and lay with him; and he perceived not when she lay down, nor when she arose.'); -INSERT INTO t1(docid,words) VALUES(1019036,'Thus were both the daughters of Lot with child by their father.'); -INSERT INTO t1(docid,words) VALUES(1019037,'And the first born bare a son, and called his name Moab: the same is the father of the Moabites unto this day.'); -INSERT INTO t1(docid,words) VALUES(1019038,'And the younger, she also bare a son, and called his name Benammi: the same is the father of the children of Ammon unto this day.'); -INSERT INTO t1(docid,words) VALUES(1020001,'And Abraham journeyed from thence toward the south country, and dwelled between Kadesh and Shur, and sojourned in Gerar.'); -INSERT INTO t1(docid,words) VALUES(1020002,'And Abraham said of Sarah his wife, She is my sister: and Abimelech king of Gerar sent, and took Sarah.'); -INSERT INTO t1(docid,words) VALUES(1020003,'But God came to Abimelech in a dream by night, and said to him, Behold, thou art but a dead man, for the woman which thou hast taken; for she is a man''s wife.'); -INSERT INTO t1(docid,words) VALUES(1020004,'But Abimelech had not come near her: and he said, LORD, wilt thou slay also a righteous nation?'); -INSERT INTO t1(docid,words) VALUES(1020005,'Said he not unto me, She is my sister? and she, even she herself said, He is my brother: in the integrity of my heart and innocency of my hands have I done this.'); -INSERT INTO t1(docid,words) VALUES(1020006,'And God said unto him in a dream, Yea, I know that thou didst this in the integrity of thy heart; for I also withheld thee from sinning against me: therefore suffered I thee not to touch her.'); -INSERT INTO t1(docid,words) VALUES(1020007,'Now therefore restore the man his wife; for he is a prophet, and he shall pray for thee, and thou shalt live: and if thou restore her not, know thou that thou shalt surely die, thou, and all that are thine.'); -INSERT INTO t1(docid,words) VALUES(1020008,'Therefore Abimelech rose early in the morning, and called all his servants, and told all these things in their ears: and the men were sore afraid.'); -INSERT INTO t1(docid,words) VALUES(1020009,'Then Abimelech called Abraham, and said unto him, What hast thou done unto us? and what have I offended thee, that thou hast brought on me and on my kingdom a great sin? thou hast done deeds unto me that ought not to be done.'); -INSERT INTO t1(docid,words) VALUES(1020010,'And Abimelech said unto Abraham, What sawest thou, that thou hast done this thing?'); -INSERT INTO t1(docid,words) VALUES(1020011,'And Abraham said, Because I thought, Surely the fear of God is not in this place; and they will slay me for my wife''s sake.'); -INSERT INTO t1(docid,words) VALUES(1020012,'And yet indeed she is my sister; she is the daughter of my father, but not the daughter of my mother; and she became my wife.'); -INSERT INTO t1(docid,words) VALUES(1020013,'And it came to pass, when God caused me to wander from my father''s house, that I said unto her, This is thy kindness which thou shalt shew unto me; at every place whither we shall come, say of me, He is my brother.'); -INSERT INTO t1(docid,words) VALUES(1020014,'And Abimelech took sheep, and oxen, and menservants, and womenservants, and gave them unto Abraham, and restored him Sarah his wife.'); -INSERT INTO t1(docid,words) VALUES(1020015,'And Abimelech said, Behold, my land is before thee: dwell where it pleaseth thee.'); -INSERT INTO t1(docid,words) VALUES(1020016,'And unto Sarah he said, Behold, I have given thy brother a thousand pieces of silver: behold, he is to thee a covering of the eyes, unto all that are with thee, and with all other: thus she was reproved.'); -INSERT INTO t1(docid,words) VALUES(1020017,'So Abraham prayed unto God: and God healed Abimelech, and his wife, and his maidservants; and they bare children.'); -INSERT INTO t1(docid,words) VALUES(1020018,'For the LORD had fast closed up all the wombs of the house of Abimelech, because of Sarah Abraham''s wife.'); -INSERT INTO t1(docid,words) VALUES(1021001,'And the LORD visited Sarah as he had said, and the LORD did unto Sarah as he had spoken.'); -INSERT INTO t1(docid,words) VALUES(1021002,'For Sarah conceived, and bare Abraham a son in his old age, at the set time of which God had spoken to him.'); -INSERT INTO t1(docid,words) VALUES(1021003,'And Abraham called the name of his son that was born unto him, whom Sarah bare to him, Isaac.'); -INSERT INTO t1(docid,words) VALUES(1021004,'And Abraham circumcised his son Isaac being eight days old, as God had commanded him.'); -INSERT INTO t1(docid,words) VALUES(1021005,'And Abraham was an hundred years old, when his son Isaac was born unto him.'); -INSERT INTO t1(docid,words) VALUES(1021006,'And Sarah said, God hath made me to laugh, so that all that hear will laugh with me.'); -INSERT INTO t1(docid,words) VALUES(1021007,'And she said, Who would have said unto Abraham, that Sarah should have given children suck? for I have born him a son in his old age.'); -INSERT INTO t1(docid,words) VALUES(1021008,'And the child grew, and was weaned: and Abraham made a great feast the same day that Isaac was weaned.'); -INSERT INTO t1(docid,words) VALUES(1021009,'And Sarah saw the son of Hagar the Egyptian, which she had born unto Abraham, mocking.'); -INSERT INTO t1(docid,words) VALUES(1021010,'Wherefore she said unto Abraham, Cast out this bondwoman and her son: for the son of this bondwoman shall not be heir with my son, even with Isaac.'); -INSERT INTO t1(docid,words) VALUES(1021011,'And the thing was very grievous in Abraham''s sight because of his son.'); -INSERT INTO t1(docid,words) VALUES(1021012,'And God said unto Abraham, Let it not be grievous in thy sight because of the lad, and because of thy bondwoman; in all that Sarah hath said unto thee, hearken unto her voice; for in Isaac shall thy seed be called.'); -INSERT INTO t1(docid,words) VALUES(1021013,'And also of the son of the bondwoman will I make a nation, because he is thy seed.'); -INSERT INTO t1(docid,words) VALUES(1021014,'And Abraham rose up early in the morning, and took bread, and a bottle of water, and gave it unto Hagar, putting it on her shoulder, and the child, and sent her away: and she departed, and wandered in the wilderness of Beersheba.'); -INSERT INTO t1(docid,words) VALUES(1021015,'And the water was spent in the bottle, and she cast the child under one of the shrubs.'); -INSERT INTO t1(docid,words) VALUES(1021016,'And she went, and sat her down over against him a good way off, as it were a bow shot: for she said, Let me not see the death of the child. And she sat over against him, and lift up her voice, and wept.'); -INSERT INTO t1(docid,words) VALUES(1021017,'And God heard the voice of the lad; and the angel of God called to Hagar out of heaven, and said unto her, What aileth thee, Hagar? fear not; for God hath heard the voice of the lad where he is.'); -INSERT INTO t1(docid,words) VALUES(1021018,'Arise, lift up the lad, and hold him in thine hand; for I will make him a great nation.'); -INSERT INTO t1(docid,words) VALUES(1021019,'And God opened her eyes, and she saw a well of water; and she went, and filled the bottle with water, and gave the lad drink.'); -INSERT INTO t1(docid,words) VALUES(1021020,'And God was with the lad; and he grew, and dwelt in the wilderness, and became an archer.'); -INSERT INTO t1(docid,words) VALUES(1021021,'And he dwelt in the wilderness of Paran: and his mother took him a wife out of the land of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1021022,'And it came to pass at that time, that Abimelech and Phichol the chief captain of his host spake unto Abraham, saying, God is with thee in all that thou doest:'); -INSERT INTO t1(docid,words) VALUES(1021023,'Now therefore swear unto me here by God that thou wilt not deal falsely with me, nor with my son, nor with my son''s son: but according to the kindness that I have done unto thee, thou shalt do unto me, and to the land wherein thou hast sojourned.'); -INSERT INTO t1(docid,words) VALUES(1021024,'And Abraham said, I will swear.'); -INSERT INTO t1(docid,words) VALUES(1021025,'And Abraham reproved Abimelech because of a well of water, which Abimelech''s servants had violently taken away.'); -INSERT INTO t1(docid,words) VALUES(1021026,'And Abimelech said, I wot not who hath done this thing; neither didst thou tell me, neither yet heard I of it, but to day.'); -INSERT INTO t1(docid,words) VALUES(1021027,'And Abraham took sheep and oxen, and gave them unto Abimelech; and both of them made a covenant.'); -INSERT INTO t1(docid,words) VALUES(1021028,'And Abraham set seven ewe lambs of the flock by themselves.'); -INSERT INTO t1(docid,words) VALUES(1021029,'And Abimelech said unto Abraham, What mean these seven ewe lambs which thou hast set by themselves?'); -INSERT INTO t1(docid,words) VALUES(1021030,'And he said, For these seven ewe lambs shalt thou take of my hand, that they may be a witness unto me, that I have digged this well.'); -INSERT INTO t1(docid,words) VALUES(1021031,'Wherefore he called that place Beersheba; because there they sware both of them.'); -INSERT INTO t1(docid,words) VALUES(1021032,'Thus they made a covenant at Beersheba: then Abimelech rose up, and Phichol the chief captain of his host, and they returned into the land of the Philistines.'); -INSERT INTO t1(docid,words) VALUES(1021033,'And Abraham planted a grove in Beersheba, and called there on the name of the LORD, the everlasting God.'); -INSERT INTO t1(docid,words) VALUES(1021034,'And Abraham sojourned in the Philistines'' land many days.'); -INSERT INTO t1(docid,words) VALUES(1022001,'And it came to pass after these things, that God did tempt Abraham, and said unto him, Abraham: and he said, Behold, here I am.'); -INSERT INTO t1(docid,words) VALUES(1022002,'And he said, Take now thy son, thine only son Isaac, whom thou lovest, and get thee into the land of Moriah; and offer him there for a burnt offering upon one of the mountains which I will tell thee of.'); -INSERT INTO t1(docid,words) VALUES(1022003,'And Abraham rose up early in the morning, and saddled his ass, and took two of his young men with him, and Isaac his son, and clave the wood for the burnt offering, and rose up, and went unto the place of which God had told him.'); -INSERT INTO t1(docid,words) VALUES(1022004,'Then on the third day Abraham lifted up his eyes, and saw the place afar off.'); -INSERT INTO t1(docid,words) VALUES(1022005,'And Abraham said unto his young men, Abide ye here with the ass; and I and the lad will go yonder and worship, and come again to you.'); -INSERT INTO t1(docid,words) VALUES(1022006,'And Abraham took the wood of the burnt offering, and laid it upon Isaac his son; and he took the fire in his hand, and a knife; and they went both of them together.'); -INSERT INTO t1(docid,words) VALUES(1022007,'And Isaac spake unto Abraham his father, and said, My father: and he said, Here am I, my son. And he said, Behold the fire and the wood: but where is the lamb for a burnt offering?'); -INSERT INTO t1(docid,words) VALUES(1022008,'And Abraham said, My son, God will provide himself a lamb for a burnt offering: so they went both of them together.'); -INSERT INTO t1(docid,words) VALUES(1022009,'And they came to the place which God had told him of; and Abraham built an altar there, and laid the wood in order, and bound Isaac his son, and laid him on the altar upon the wood.'); -INSERT INTO t1(docid,words) VALUES(1022010,'And Abraham stretched forth his hand, and took the knife to slay his son.'); -INSERT INTO t1(docid,words) VALUES(1022011,'And the angel of the LORD called unto him out of heaven, and said, Abraham, Abraham: and he said, Here am I.'); -INSERT INTO t1(docid,words) VALUES(1022012,'And he said, Lay not thine hand upon the lad, neither do thou any thing unto him: for now I know that thou fearest God, seeing thou hast not withheld thy son, thine only son from me.'); -INSERT INTO t1(docid,words) VALUES(1022013,'And Abraham lifted up his eyes, and looked, and behold behind him a ram caught in a thicket by his horns: and Abraham went and took the ram, and offered him up for a burnt offering in the stead of his son.'); -INSERT INTO t1(docid,words) VALUES(1022014,'And Abraham called the name of that place Jehovahjireh: as it is said to this day, In the mount of the LORD it shall be seen.'); -INSERT INTO t1(docid,words) VALUES(1022015,'And the angel of the LORD called unto Abraham out of heaven the second time,'); -INSERT INTO t1(docid,words) VALUES(1022016,'And said, By myself have I sworn, saith the LORD, for because thou hast done this thing, and hast not withheld thy son, thine only son:'); -INSERT INTO t1(docid,words) VALUES(1022017,'That in blessing I will bless thee, and in multiplying I will multiply thy seed as the stars of the heaven, and as the sand which is upon the sea shore; and thy seed shall possess the gate of his enemies;'); -INSERT INTO t1(docid,words) VALUES(1022018,'And in thy seed shall all the nations of the earth be blessed; because thou hast obeyed my voice.'); -INSERT INTO t1(docid,words) VALUES(1022019,'So Abraham returned unto his young men, and they rose up and went together to Beersheba; and Abraham dwelt at Beersheba.'); -INSERT INTO t1(docid,words) VALUES(1022020,'And it came to pass after these things, that it was told Abraham, saying, Behold, Milcah, she hath also born children unto thy brother Nahor;'); -INSERT INTO t1(docid,words) VALUES(1022021,'Huz his firstborn, and Buz his brother, and Kemuel the father of Aram,'); -INSERT INTO t1(docid,words) VALUES(1022022,'And Chesed, and Hazo, and Pildash, and Jidlaph, and Bethuel.'); -INSERT INTO t1(docid,words) VALUES(1022023,'And Bethuel begat Rebekah: these eight Milcah did bear to Nahor, Abraham''s brother.'); -INSERT INTO t1(docid,words) VALUES(1022024,'And his concubine, whose name was Reumah, she bare also Tebah, and Gaham, and Thahash, and Maachah.'); -INSERT INTO t1(docid,words) VALUES(1023001,'And Sarah was an hundred and seven and twenty years old: these were the years of the life of Sarah.'); -INSERT INTO t1(docid,words) VALUES(1023002,'And Sarah died in Kirjatharba; the same is Hebron in the land of Canaan: and Abraham came to mourn for Sarah, and to weep for her.'); -INSERT INTO t1(docid,words) VALUES(1023003,'And Abraham stood up from before his dead, and spake unto the sons of Heth, saying,'); -INSERT INTO t1(docid,words) VALUES(1023004,'I am a stranger and a sojourner with you: give me a possession of a buryingplace with you, that I may bury my dead out of my sight.'); -INSERT INTO t1(docid,words) VALUES(1023005,'And the children of Heth answered Abraham, saying unto him,'); -INSERT INTO t1(docid,words) VALUES(1023006,'Hear us, my lord: thou art a mighty prince among us: in the choice of our sepulchres bury thy dead; none of us shall withhold from thee his sepulchre, but that thou mayest bury thy dead.'); -INSERT INTO t1(docid,words) VALUES(1023007,'And Abraham stood up, and bowed himself to the people of the land, even to the children of Heth.'); -INSERT INTO t1(docid,words) VALUES(1023008,'And he communed with them, saying, If it be your mind that I should bury my dead out of my sight; hear me, and intreat for me to Ephron the son of Zohar,'); -INSERT INTO t1(docid,words) VALUES(1023009,'That he may give me the cave of Machpelah, which he hath, which is in the end of his field; for as much money as it is worth he shall give it me for a possession of a buryingplace amongst you.'); -INSERT INTO t1(docid,words) VALUES(1023010,'And Ephron dwelt among the children of Heth: and Ephron the Hittite answered Abraham in the audience of the children of Heth, even of all that went in at the gate of his city, saying,'); -INSERT INTO t1(docid,words) VALUES(1023011,'Nay, my lord, hear me: the field give I thee, and the cave that is therein, I give it thee; in the presence of the sons of my people give I it thee: bury thy dead.'); -INSERT INTO t1(docid,words) VALUES(1023012,'And Abraham bowed down himself before the people of the land.'); -INSERT INTO t1(docid,words) VALUES(1023013,'And he spake unto Ephron in the audience of the people of the land, saying, But if thou wilt give it, I pray thee, hear me: I will give thee money for the field; take it of me, and I will bury my dead there.'); -INSERT INTO t1(docid,words) VALUES(1023014,'And Ephron answered Abraham, saying unto him,'); -INSERT INTO t1(docid,words) VALUES(1023015,'My lord, hearken unto me: the land is worth four hundred shekels of silver; what is that betwixt me and thee? bury therefore thy dead.'); -INSERT INTO t1(docid,words) VALUES(1023016,'And Abraham hearkened unto Ephron; and Abraham weighed to Ephron the silver, which he had named in the audience of the sons of Heth, four hundred shekels of silver, current money with the merchant.'); -INSERT INTO t1(docid,words) VALUES(1023017,'And the field of Ephron which was in Machpelah, which was before Mamre, the field, and the cave which was therein, and all the trees that were in the field, that were in all the borders round about, were made sure'); -INSERT INTO t1(docid,words) VALUES(1023018,'Unto Abraham for a possession in the presence of the children of Heth, before all that went in at the gate of his city.'); -INSERT INTO t1(docid,words) VALUES(1023019,'And after this, Abraham buried Sarah his wife in the cave of the field of Machpelah before Mamre: the same is Hebron in the land of Canaan.'); -INSERT INTO t1(docid,words) VALUES(1023020,'And the field, and the cave that is therein, were made sure unto Abraham for a possession of a buryingplace by the sons of Heth.'); -INSERT INTO t1(docid,words) VALUES(1024001,'And Abraham was old, and well stricken in age: and the LORD had blessed Abraham in all things.'); -INSERT INTO t1(docid,words) VALUES(1024002,'And Abraham said unto his eldest servant of his house, that ruled over all that he had, Put, I pray thee, thy hand under my thigh:'); -INSERT INTO t1(docid,words) VALUES(1024003,'And I will make thee swear by the LORD, the God of heaven, and the God of the earth, that thou shalt not take a wife unto my son of the daughters of the Canaanites, among whom I dwell:'); -INSERT INTO t1(docid,words) VALUES(1024004,'But thou shalt go unto my country, and to my kindred, and take a wife unto my son Isaac.'); -INSERT INTO t1(docid,words) VALUES(1024005,'And the servant said unto him, Peradventure the woman will not be willing to follow me unto this land: must I needs bring thy son again unto the land from whence thou camest?'); -INSERT INTO t1(docid,words) VALUES(1024006,'And Abraham said unto him, Beware thou that thou bring not my son thither again.'); -INSERT INTO t1(docid,words) VALUES(1024007,'The LORD God of heaven, which took me from my father''s house, and from the land of my kindred, and which spake unto me, and that sware unto me, saying, Unto thy seed will I give this land; he shall send his angel before thee, and thou shalt take a wife unto my son from thence.'); -INSERT INTO t1(docid,words) VALUES(1024008,'And if the woman will not be willing to follow thee, then thou shalt be clear from this my oath: only bring not my son thither again.'); -INSERT INTO t1(docid,words) VALUES(1024009,'And the servant put his hand under the thigh of Abraham his master, and sware to him concerning that matter.'); -INSERT INTO t1(docid,words) VALUES(1024010,'And the servant took ten camels of the camels of his master, and departed; for all the goods of his master were in his hand: and he arose, and went to Mesopotamia, unto the city of Nahor.'); -INSERT INTO t1(docid,words) VALUES(1024011,'And he made his camels to kneel down without the city by a well of water at the time of the evening, even the time that women go out to draw water.'); -INSERT INTO t1(docid,words) VALUES(1024012,'And he said O LORD God of my master Abraham, I pray thee, send me good speed this day, and shew kindness unto my master Abraham.'); -INSERT INTO t1(docid,words) VALUES(1024013,'Behold, I stand here by the well of water; and the daughters of the men of the city come out to draw water:'); -INSERT INTO t1(docid,words) VALUES(1024014,'And let it come to pass, that the damsel to whom I shall say, Let down thy pitcher, I pray thee, that I may drink; and she shall say, Drink, and I will give thy camels drink also: let the same be she that thou hast appointed for thy servant Isaac; and thereby shall I know that thou hast shewed kindness unto my master.'); -INSERT INTO t1(docid,words) VALUES(1024015,'And it came to pass, before he had done speaking, that, behold, Rebekah came out, who was born to Bethuel, son of Milcah, the wife of Nahor, Abraham''s brother, with her pitcher upon her shoulder.'); -INSERT INTO t1(docid,words) VALUES(1024016,'And the damsel was very fair to look upon, a virgin, neither had any man known her: and she went down to the well, and filled her pitcher, and came up.'); -INSERT INTO t1(docid,words) VALUES(1024017,'And the servant ran to meet her, and said, Let me, I pray thee, drink a little water of thy pitcher.'); -INSERT INTO t1(docid,words) VALUES(1024018,'And she said, Drink, my lord: and she hasted, and let down her pitcher upon her hand, and gave him drink.'); -INSERT INTO t1(docid,words) VALUES(1024019,'And when she had done giving him drink, she said, I will draw water for thy camels also, until they have done drinking.'); -INSERT INTO t1(docid,words) VALUES(1024020,'And she hasted, and emptied her pitcher into the trough, and ran again unto the well to draw water, and drew for all his camels.'); -INSERT INTO t1(docid,words) VALUES(1024021,'And the man wondering at her held his peace, to wit whether the LORD had made his journey prosperous or not.'); -INSERT INTO t1(docid,words) VALUES(1024022,'And it came to pass, as the camels had done drinking, that the man took a golden earring of half a shekel weight, and two bracelets for her hands of ten shekels weight of gold;'); -INSERT INTO t1(docid,words) VALUES(1024023,'And said, Whose daughter art thou? tell me, I pray thee: is there room in thy father''s house for us to lodge in?'); -INSERT INTO t1(docid,words) VALUES(1024024,'And she said unto him, I am the daughter of Bethuel the son of Milcah, which she bare unto Nahor.'); -INSERT INTO t1(docid,words) VALUES(1024025,'She said moreover unto him, We have both straw and provender enough, and room to lodge in.'); -INSERT INTO t1(docid,words) VALUES(1024026,'And the man bowed down his head, and worshipped the LORD.'); -INSERT INTO t1(docid,words) VALUES(1024027,'And he said, Blessed be the LORD God of my master Abraham, who hath not left destitute my master of his mercy and his truth: I being in the way, the LORD led me to the house of my master''s brethren.'); -INSERT INTO t1(docid,words) VALUES(1024028,'And the damsel ran, and told them of her mother''s house these things.'); -INSERT INTO t1(docid,words) VALUES(1024029,'And Rebekah had a brother, and his name was Laban: and Laban ran out unto the man, unto the well.'); -INSERT INTO t1(docid,words) VALUES(1024030,'And it came to pass, when he saw the earring and bracelets upon his sister''s hands, and when he heard the words of Rebekah his sister, saying, Thus spake the man unto me; that he came unto the man; and, behold, he stood by the camels at the well.'); -INSERT INTO t1(docid,words) VALUES(1024031,'And he said, Come in, thou blessed of the LORD; wherefore standest thou without? for I have prepared the house, and room for the camels.'); -INSERT INTO t1(docid,words) VALUES(1024032,'And the man came into the house: and he ungirded his camels, and gave straw and provender for the camels, and water to wash his feet, and the men''s feet that were with him.'); -INSERT INTO t1(docid,words) VALUES(1024033,'And there was set meat before him to eat: but he said, I will not eat, until I have told mine errand. And he said, Speak on.'); -INSERT INTO t1(docid,words) VALUES(1024034,'And he said, I am Abraham''s servant.'); -INSERT INTO t1(docid,words) VALUES(1024035,'And the LORD hath blessed my master greatly; and he is become great: and he hath given him flocks, and herds, and silver, and gold, and menservants, and maidservants, and camels, and asses.'); -INSERT INTO t1(docid,words) VALUES(1024036,'And Sarah my master''s wife bare a son to my master when she was old: and unto him hath he given all that he hath.'); -INSERT INTO t1(docid,words) VALUES(1024037,'And my master made me swear, saying, Thou shalt not take a wife to my son of the daughters of the Canaanites, in whose land I dwell:'); -INSERT INTO t1(docid,words) VALUES(1024038,'But thou shalt go unto my father''s house, and to my kindred, and take a wife unto my son.'); -INSERT INTO t1(docid,words) VALUES(1024039,'And I said unto my master, Peradventure the woman will not follow me.'); -INSERT INTO t1(docid,words) VALUES(1024040,'And he said unto me, The LORD, before whom I walk, will send his angel with thee, and prosper thy way; and thou shalt take a wife for my son of my kindred, and of my father''s house:'); -INSERT INTO t1(docid,words) VALUES(1024041,'Then shalt thou be clear from this my oath, when thou comest to my kindred; and if they give not thee one, thou shalt be clear from my oath.'); -INSERT INTO t1(docid,words) VALUES(1024042,'And I came this day unto the well, and said, O LORD God of my master Abraham, if now thou do prosper my way which I go:'); -INSERT INTO t1(docid,words) VALUES(1024043,'Behold, I stand by the well of water; and it shall come to pass, that when the virgin cometh forth to draw water, and I say to her, Give me, I pray thee, a little water of thy pitcher to drink;'); -INSERT INTO t1(docid,words) VALUES(1024044,'And she say to me, Both drink thou, and I will also draw for thy camels: let the same be the woman whom the LORD hath appointed out for my master''s son.'); -INSERT INTO t1(docid,words) VALUES(1024045,'And before I had done speaking in mine heart, behold, Rebekah came forth with her pitcher on her shoulder; and she went down unto the well, and drew water: and I said unto her, Let me drink, I pray thee.'); -INSERT INTO t1(docid,words) VALUES(1024046,'And she made haste, and let down her pitcher from her shoulder, and said, Drink, and I will give thy camels drink also: so I drank, and she made the camels drink also.'); -INSERT INTO t1(docid,words) VALUES(1024047,'And I asked her, and said, Whose daughter art thou? And she said, the daughter of Bethuel, Nahor''s son, whom Milcah bare unto him: and I put the earring upon her face, and the bracelets upon her hands.'); -INSERT INTO t1(docid,words) VALUES(1024048,'And I bowed down my head, and worshipped the LORD, and blessed the LORD God of my master Abraham, which had led me in the right way to take my master''s brother''s daughter unto his son.'); -INSERT INTO t1(docid,words) VALUES(1024049,'And now if ye will deal kindly and truly with my master, tell me: and if not, tell me; that I may turn to the right hand, or to the left.'); -INSERT INTO t1(docid,words) VALUES(1024050,'Then Laban and Bethuel answered and said, The thing proceedeth from the LORD: we cannot speak unto thee bad or good.'); -INSERT INTO t1(docid,words) VALUES(1024051,'Behold, Rebekah is before thee, take her, and go, and let her be thy master''s son''s wife, as the LORD hath spoken.'); -INSERT INTO t1(docid,words) VALUES(1024052,'And it came to pass, that, when Abraham''s servant heard their words, he worshipped the LORD, bowing himself to the earth.'); -INSERT INTO t1(docid,words) VALUES(1024053,'And the servant brought forth jewels of silver, and jewels of gold, and raiment, and gave them to Rebekah: he gave also to her brother and to her mother precious things.'); -INSERT INTO t1(docid,words) VALUES(1024054,'And they did eat and drink, he and the men that were with him, and tarried all night; and they rose up in the morning, and he said, Send me away unto my master.'); -INSERT INTO t1(docid,words) VALUES(1024055,'And her brother and her mother said, Let the damsel abide with us a few days, at the least ten; after that she shall go.'); -INSERT INTO t1(docid,words) VALUES(1024056,'And he said unto them, Hinder me not, seeing the LORD hath prospered my way; send me away that I may go to my master.'); -INSERT INTO t1(docid,words) VALUES(1024057,'And they said, We will call the damsel, and enquire at her mouth.'); -INSERT INTO t1(docid,words) VALUES(1024058,'And they called Rebekah, and said unto her, Wilt thou go with this man? And she said, I will go.'); -INSERT INTO t1(docid,words) VALUES(1024059,'And they sent away Rebekah their sister, and her nurse, and Abraham''s servant, and his men.'); -INSERT INTO t1(docid,words) VALUES(1024060,'And they blessed Rebekah, and said unto her, Thou art our sister, be thou the mother of thousands of millions, and let thy seed possess the gate of those which hate them.'); -INSERT INTO t1(docid,words) VALUES(1024061,'And Rebekah arose, and her damsels, and they rode upon the camels, and followed the man: and the servant took Rebekah, and went his way.'); -INSERT INTO t1(docid,words) VALUES(1024062,'And Isaac came from the way of the well Lahairoi; for he dwelt in the south country.'); -INSERT INTO t1(docid,words) VALUES(1024063,'And Isaac went out to meditate in the field at the eventide: and he lifted up his eyes, and saw, and, behold, the camels were coming.'); -INSERT INTO t1(docid,words) VALUES(1024064,'And Rebekah lifted up her eyes, and when she saw Isaac, she lighted off the camel.'); -INSERT INTO t1(docid,words) VALUES(1024065,'For she had said unto the servant, What man is this that walketh in the field to meet us? And the servant had said, It is my master: therefore she took a vail, and covered herself.'); -INSERT INTO t1(docid,words) VALUES(1024066,'And the servant told Isaac all things that he had done.'); -INSERT INTO t1(docid,words) VALUES(1024067,'And Isaac brought her into his mother Sarah''s tent, and took Rebekah, and she became his wife; and he loved her: and Isaac was comforted after his mother''s death.'); -INSERT INTO t1(docid,words) VALUES(1025001,'Then again Abraham took a wife, and her name was Keturah.'); -INSERT INTO t1(docid,words) VALUES(1025002,'And she bare him Zimran, and Jokshan, and Medan, and Midian, and Ishbak, and Shuah.'); -INSERT INTO t1(docid,words) VALUES(1025003,'And Jokshan begat Sheba, and Dedan. And the sons of Dedan were Asshurim, and Letushim, and Leummim.'); -INSERT INTO t1(docid,words) VALUES(1025004,'And the sons of Midian; Ephah, and Epher, and Hanoch, and Abidah, and Eldaah. All these were the children of Keturah.'); -INSERT INTO t1(docid,words) VALUES(1025005,'And Abraham gave all that he had unto Isaac.'); -INSERT INTO t1(docid,words) VALUES(1025006,'But unto the sons of the concubines, which Abraham had, Abraham gave gifts, and sent them away from Isaac his son, while he yet lived, eastward, unto the east country.'); -INSERT INTO t1(docid,words) VALUES(1025007,'And these are the days of the years of Abraham''s life which he lived, an hundred threescore and fifteen years.'); -INSERT INTO t1(docid,words) VALUES(1025008,'Then Abraham gave up the ghost, and died in a good old age, an old man, and full of years; and was gathered to his people.'); -INSERT INTO t1(docid,words) VALUES(1025009,'And his sons Isaac and Ishmael buried him in the cave of Machpelah, in the field of Ephron the son of Zohar the Hittite, which is before Mamre;'); -INSERT INTO t1(docid,words) VALUES(1025010,'The field which Abraham purchased of the sons of Heth: there was Abraham buried, and Sarah his wife.'); -INSERT INTO t1(docid,words) VALUES(1025011,'And it came to pass after the death of Abraham, that God blessed his son Isaac; and Isaac dwelt by the well Lahairoi.'); -INSERT INTO t1(docid,words) VALUES(1025012,'Now these are the generations of Ishmael, Abraham''s son, whom Hagar the Egyptian, Sarah''s handmaid, bare unto Abraham:'); -INSERT INTO t1(docid,words) VALUES(1025013,'And these are the names of the sons of Ishmael, by their names, according to their generations: the firstborn of Ishmael, Nebajoth; and Kedar, and Adbeel, and Mibsam,'); -INSERT INTO t1(docid,words) VALUES(1025014,'And Mishma, and Dumah, and Massa,'); -INSERT INTO t1(docid,words) VALUES(1025015,'Hadar, and Tema, Jetur, Naphish, and Kedemah:'); -INSERT INTO t1(docid,words) VALUES(1025016,'These are the sons of Ishmael, and these are their names, by their towns, and by their castles; twelve princes according to their nations.'); -INSERT INTO t1(docid,words) VALUES(1025017,'And these are the years of the life of Ishmael, an hundred and thirty and seven years: and he gave up the ghost and died; and was gathered unto his people.'); -INSERT INTO t1(docid,words) VALUES(1025018,'And they dwelt from Havilah unto Shur, that is before Egypt, as thou goest toward Assyria: and he died in the presence of all his brethren.'); -INSERT INTO t1(docid,words) VALUES(1025019,'And these are the generations of Isaac, Abraham''s son: Abraham begat Isaac:'); -INSERT INTO t1(docid,words) VALUES(1025020,'And Isaac was forty years old when he took Rebekah to wife, the daughter of Bethuel the Syrian of Padanaram, the sister to Laban the Syrian.'); -INSERT INTO t1(docid,words) VALUES(1025021,'And Isaac intreated the LORD for his wife, because she was barren: and the LORD was intreated of him, and Rebekah his wife conceived.'); -INSERT INTO t1(docid,words) VALUES(1025022,'And the children struggled together within her; and she said, If it be so, why am I thus? And she went to enquire of the LORD.'); -INSERT INTO t1(docid,words) VALUES(1025023,'And the LORD said unto her, Two nations are in thy womb, and two manner of people shall be separated from thy bowels; and the one people shall be stronger than the other people; and the elder shall serve the younger.'); -INSERT INTO t1(docid,words) VALUES(1025024,'And when her days to be delivered were fulfilled, behold, there were twins in her womb.'); -INSERT INTO t1(docid,words) VALUES(1025025,'And the first came out red, all over like an hairy garment; and they called his name Esau.'); -INSERT INTO t1(docid,words) VALUES(1025026,'And after that came his brother out, and his hand took hold on Esau''s heel; and his name was called Jacob: and Isaac was threescore years old when she bare them.'); -INSERT INTO t1(docid,words) VALUES(1025027,'And the boys grew: and Esau was a cunning hunter, a man of the field; and Jacob was a plain man, dwelling in tents.'); -INSERT INTO t1(docid,words) VALUES(1025028,'And Isaac loved Esau, because he did eat of his venison: but Rebekah loved Jacob.'); -INSERT INTO t1(docid,words) VALUES(1025029,'And Jacob sod pottage: and Esau came from the field, and he was faint:'); -INSERT INTO t1(docid,words) VALUES(1025030,'And Esau said to Jacob, Feed me, I pray thee, with that same red pottage; for I am faint: therefore was his name called Edom.'); -INSERT INTO t1(docid,words) VALUES(1025031,'And Jacob said, Sell me this day thy birthright.'); -INSERT INTO t1(docid,words) VALUES(1025032,'And Esau said, Behold, I am at the point to die: and what profit shall this birthright do to me?'); -INSERT INTO t1(docid,words) VALUES(1025033,'And Jacob said, Swear to me this day; and he sware unto him: and he sold his birthright unto Jacob.'); -INSERT INTO t1(docid,words) VALUES(1025034,'Then Jacob gave Esau bread and pottage of lentiles; and he did eat and drink, and rose up, and went his way: thus Esau despised his birthright.'); -INSERT INTO t1(docid,words) VALUES(1026001,'And there was a famine in the land, beside the first famine that was in the days of Abraham. And Isaac went unto Abimelech king of the Philistines unto Gerar.'); -INSERT INTO t1(docid,words) VALUES(1026002,'And the LORD appeared unto him, and said, Go not down into Egypt; dwell in the land which I shall tell thee of:'); -INSERT INTO t1(docid,words) VALUES(1026003,'Sojourn in this land, and I will be with thee, and will bless thee; for unto thee, and unto thy seed, I will give all these countries, and I will perform the oath which I sware unto Abraham thy father;'); -INSERT INTO t1(docid,words) VALUES(1026004,'And I will make thy seed to multiply as the stars of heaven, and will give unto thy seed all these countries; and in thy seed shall all the nations of the earth be blessed;'); -INSERT INTO t1(docid,words) VALUES(1026005,'Because that Abraham obeyed my voice, and kept my charge, my commandments, my statutes, and my laws.'); -INSERT INTO t1(docid,words) VALUES(1026006,'And Isaac dwelt in Gerar:'); -INSERT INTO t1(docid,words) VALUES(1026007,'And the men of the place asked him of his wife; and he said, She is my sister: for he feared to say, She is my wife; lest, said he, the men of the place should kill me for Rebekah; because she was fair to look upon.'); -INSERT INTO t1(docid,words) VALUES(1026008,'And it came to pass, when he had been there a long time, that Abimelech king of the Philistines looked out at a window, and saw, and, behold, Isaac was sporting with Rebekah his wife.'); -INSERT INTO t1(docid,words) VALUES(1026009,'And Abimelech called Isaac, and said, Behold, of a surety she is thy wife; and how saidst thou, She is my sister? And Isaac said unto him, Because I said, Lest I die for her.'); -INSERT INTO t1(docid,words) VALUES(1026010,'And Abimelech said, What is this thou hast done unto us? one of the people might lightly have lien with thy wife, and thou shouldest have brought guiltiness upon us.'); -INSERT INTO t1(docid,words) VALUES(1026011,'And Abimelech charged all his people, saying, He that toucheth this man or his wife shall surely be put to death.'); -INSERT INTO t1(docid,words) VALUES(1026012,'Then Isaac sowed in that land, and received in the same year an hundredfold: and the LORD blessed him.'); -INSERT INTO t1(docid,words) VALUES(1026013,'And the man waxed great, and went forward, and grew until he became very great:'); -INSERT INTO t1(docid,words) VALUES(1026014,'For he had possession of flocks, and possession of herds, and great store of servants: and the Philistines envied him.'); -INSERT INTO t1(docid,words) VALUES(1026015,'For all the wells which his father''s servants had digged in the days of Abraham his father, the Philistines had stopped them, and filled them with earth.'); -INSERT INTO t1(docid,words) VALUES(1026016,'And Abimelech said unto Isaac, Go from us; for thou art much mightier than we.'); -INSERT INTO t1(docid,words) VALUES(1026017,'And Isaac departed thence, and pitched his tent in the valley of Gerar, and dwelt there.'); -INSERT INTO t1(docid,words) VALUES(1026018,'And Isaac digged again the wells of water, which they had digged in the days of Abraham his father; for the Philistines had stopped them after the death of Abraham: and he called their names after the names by which his father had called them.'); -INSERT INTO t1(docid,words) VALUES(1026019,'And Isaac''s servants digged in the valley, and found there a well of springing water.'); -INSERT INTO t1(docid,words) VALUES(1026020,'And the herdmen of Gerar did strive with Isaac''s herdmen, saying, The water is ours: and he called the name of the well Esek; because they strove with him.'); -INSERT INTO t1(docid,words) VALUES(1026021,'And they digged another well, and strove for that also: and he called the name of it Sitnah.'); -INSERT INTO t1(docid,words) VALUES(1026022,'And he removed from thence, and digged another well; and for that they strove not: and he called the name of it Rehoboth; and he said, For now the LORD hath made room for us, and we shall be fruitful in the land.'); -INSERT INTO t1(docid,words) VALUES(1026023,'And he went up from thence to Beersheba.'); -INSERT INTO t1(docid,words) VALUES(1026024,'And the LORD appeared unto him the same night, and said, I am the God of Abraham thy father: fear not, for I am with thee, and will bless thee, and multiply thy seed for my servant Abraham''s sake.'); -INSERT INTO t1(docid,words) VALUES(1026025,'And he builded an altar there, and called upon the name of the LORD, and pitched his tent there: and there Isaac''s servants digged a well.'); -INSERT INTO t1(docid,words) VALUES(1026026,'Then Abimelech went to him from Gerar, and Ahuzzath one of his friends, and Phichol the chief captain of his army.'); -INSERT INTO t1(docid,words) VALUES(1026027,'And Isaac said unto them, Wherefore come ye to me, seeing ye hate me, and have sent me away from you?'); -INSERT INTO t1(docid,words) VALUES(1026028,'And they said, We saw certainly that the LORD was with thee: and we said, Let there be now an oath betwixt us, even betwixt us and thee, and let us make a covenant with thee;'); -INSERT INTO t1(docid,words) VALUES(1026029,'That thou wilt do us no hurt, as we have not touched thee, and as we have done unto thee nothing but good, and have sent thee away in peace: thou art now the blessed of the LORD.'); -INSERT INTO t1(docid,words) VALUES(1026030,'And he made them a feast, and they did eat and drink.'); -INSERT INTO t1(docid,words) VALUES(1026031,'And they rose up betimes in the morning, and sware one to another: and Isaac sent them away, and they departed from him in peace.'); -INSERT INTO t1(docid,words) VALUES(1026032,'And it came to pass the same day, that Isaac''s servants came, and told him concerning the well which they had digged, and said unto him, We have found water.'); -INSERT INTO t1(docid,words) VALUES(1026033,'And he called it Shebah: therefore the name of the city is Beersheba unto this day.'); -INSERT INTO t1(docid,words) VALUES(1026034,'And Esau was forty years old when he took to wife Judith the daughter of Beeri the Hittite, and Bashemath the daughter of Elon the Hittite:'); -INSERT INTO t1(docid,words) VALUES(1026035,'Which were a grief of mind unto Isaac and to Rebekah.'); -INSERT INTO t1(docid,words) VALUES(1027001,'And it came to pass, that when Isaac was old, and his eyes were dim, so that he could not see, he called Esau his eldest son, and said unto him, My son: and he said unto him, Behold, here am I.'); -INSERT INTO t1(docid,words) VALUES(1027002,'And he said, Behold now, I am old, I know not the day of my death:'); -INSERT INTO t1(docid,words) VALUES(1027003,'Now therefore take, I pray thee, thy weapons, thy quiver and thy bow, and go out to the field, and take me some venison;'); -INSERT INTO t1(docid,words) VALUES(1027004,'And make me savoury meat, such as I love, and bring it to me, that I may eat; that my soul may bless thee before I die.'); -INSERT INTO t1(docid,words) VALUES(1027005,'And Rebekah heard when Isaac spake to Esau his son. And Esau went to the field to hunt for venison, and to bring it.'); -INSERT INTO t1(docid,words) VALUES(1027006,'And Rebekah spake unto Jacob her son, saying, Behold, I heard thy father speak unto Esau thy brother, saying,'); -INSERT INTO t1(docid,words) VALUES(1027007,'Bring me venison, and make me savoury meat, that I may eat, and bless thee before the LORD before my death.'); -INSERT INTO t1(docid,words) VALUES(1027008,'Now therefore, my son, obey my voice according to that which I command thee.'); -INSERT INTO t1(docid,words) VALUES(1027009,'Go now to the flock, and fetch me from thence two good kids of the goats; and I will make them savoury meat for thy father, such as he loveth:'); -INSERT INTO t1(docid,words) VALUES(1027010,'And thou shalt bring it to thy father, that he may eat, and that he may bless thee before his death.'); -INSERT INTO t1(docid,words) VALUES(1027011,'And Jacob said to Rebekah his mother, Behold, Esau my brother is a hairy man, and I am a smooth man:'); -INSERT INTO t1(docid,words) VALUES(1027012,'My father peradventure will feel me, and I shall seem to him as a deceiver; and I shall bring a curse upon me, and not a blessing.'); -INSERT INTO t1(docid,words) VALUES(1027013,'And his mother said unto him, Upon me be thy curse, my son: only obey my voice, and go fetch me them.'); -INSERT INTO t1(docid,words) VALUES(1027014,'And he went, and fetched, and brought them to his mother: and his mother made savoury meat, such as his father loved.'); -INSERT INTO t1(docid,words) VALUES(1027015,'And Rebekah took goodly raiment of her eldest son Esau, which were with her in the house, and put them upon Jacob her younger son:'); -INSERT INTO t1(docid,words) VALUES(1027016,'And she put the skins of the kids of the goats upon his hands, and upon the smooth of his neck:'); -INSERT INTO t1(docid,words) VALUES(1027017,'And she gave the savoury meat and the bread, which she had prepared, into the hand of her son Jacob.'); -INSERT INTO t1(docid,words) VALUES(1027018,'And he came unto his father, and said, My father: and he said, Here am I; who art thou, my son?'); -INSERT INTO t1(docid,words) VALUES(1027019,'And Jacob said unto his father, I am Esau thy first born; I have done according as thou badest me: arise, I pray thee, sit and eat of my venison, that thy soul may bless me.'); -INSERT INTO t1(docid,words) VALUES(1027020,'And Isaac said unto his son, How is it that thou hast found it so quickly, my son? And he said, Because the LORD thy God brought it to me.'); -INSERT INTO t1(docid,words) VALUES(1027021,'And Isaac said unto Jacob, Come near, I pray thee, that I may feel thee, my son, whether thou be my very son Esau or not.'); -INSERT INTO t1(docid,words) VALUES(1027022,'And Jacob went near unto Isaac his father; and he felt him, and said, The voice is Jacob''s voice, but the hands are the hands of Esau.'); -INSERT INTO t1(docid,words) VALUES(1027023,'And he discerned him not, because his hands were hairy, as his brother Esau''s hands: so he blessed him.'); -INSERT INTO t1(docid,words) VALUES(1027024,'And he said, Art thou my very son Esau? And he said, I am.'); -INSERT INTO t1(docid,words) VALUES(1027025,'And he said, Bring it near to me, and I will eat of my son''s venison, that my soul may bless thee. And he brought it near to him, and he did eat: and he brought him wine and he drank.'); -INSERT INTO t1(docid,words) VALUES(1027026,'And his father Isaac said unto him, Come near now, and kiss me, my son.'); -INSERT INTO t1(docid,words) VALUES(1027027,'And he came near, and kissed him: and he smelled the smell of his raiment, and blessed him, and said, See, the smell of my son is as the smell of a field which the LORD hath blessed:'); -INSERT INTO t1(docid,words) VALUES(1027028,'Therefore God give thee of the dew of heaven, and the fatness of the earth, and plenty of corn and wine:'); -INSERT INTO t1(docid,words) VALUES(1027029,'Let people serve thee, and nations bow down to thee: be lord over thy brethren, and let thy mother''s sons bow down to thee: cursed be every one that curseth thee, and blessed be he that blesseth thee.'); -INSERT INTO t1(docid,words) VALUES(1027030,'And it came to pass, as soon as Isaac had made an end of blessing Jacob, and Jacob was yet scarce gone out from the presence of Isaac his father, that Esau his brother came in from his hunting.'); -INSERT INTO t1(docid,words) VALUES(1027031,'And he also had made savoury meat, and brought it unto his father, and said unto his father, Let my father arise, and eat of his son''s venison, that thy soul may bless me.'); -INSERT INTO t1(docid,words) VALUES(1027032,'And Isaac his father said unto him, Who art thou? And he said, I am thy son, thy firstborn Esau.'); -INSERT INTO t1(docid,words) VALUES(1027033,'And Isaac trembled very exceedingly, and said, Who? where is he that hath taken venison, and brought it me, and I have eaten of all before thou camest, and have blessed him? yea, and he shall be blessed.'); -INSERT INTO t1(docid,words) VALUES(1027034,'And when Esau heard the words of his father, he cried with a great and exceeding bitter cry, and said unto his father, Bless me, even me also, O my father.'); -INSERT INTO t1(docid,words) VALUES(1027035,'And he said, Thy brother came with subtilty, and hath taken away thy blessing.'); -INSERT INTO t1(docid,words) VALUES(1027036,'And he said, Is not he rightly named Jacob? for he hath supplanted me these two times: he took away my birthright; and, behold, now he hath taken away my blessing. And he said, Hast thou not reserved a blessing for me?'); -INSERT INTO t1(docid,words) VALUES(1027037,'And Isaac answered and said unto Esau, Behold, I have made him thy lord, and all his brethren have I given to him for servants; and with corn and wine have I sustained him: and what shall I do now unto thee, my son?'); -INSERT INTO t1(docid,words) VALUES(1027038,'And Esau said unto his father, Hast thou but one blessing, my father? bless me, even me also, O my father. And Esau lifted up his voice, and wept.'); -INSERT INTO t1(docid,words) VALUES(1027039,'And Isaac his father answered and said unto him, Behold, thy dwelling shall be the fatness of the earth, and of the dew of heaven from above;'); -INSERT INTO t1(docid,words) VALUES(1027040,'And by thy sword shalt thou live, and shalt serve thy brother; and it shall come to pass when thou shalt have the dominion, that thou shalt break his yoke from off thy neck.'); -INSERT INTO t1(docid,words) VALUES(1027041,'And Esau hated Jacob because of the blessing wherewith his father blessed him: and Esau said in his heart, The days of mourning for my father are at hand; then will I slay my brother Jacob.'); -INSERT INTO t1(docid,words) VALUES(1027042,'And these words of Esau her elder son were told to Rebekah: and she sent and called Jacob her younger son, and said unto him, Behold, thy brother Esau, as touching thee, doth comfort himself, purposing to kill thee.'); -INSERT INTO t1(docid,words) VALUES(1027043,'Now therefore, my son, obey my voice; arise, flee thou to Laban my brother to Haran;'); -INSERT INTO t1(docid,words) VALUES(1027044,'And tarry with him a few days, until thy brother''s fury turn away;'); -INSERT INTO t1(docid,words) VALUES(1027045,'Until thy brother''s anger turn away from thee, and he forget that which thou hast done to him: then I will send, and fetch thee from thence: why should I be deprived also of you both in one day?'); -INSERT INTO t1(docid,words) VALUES(1027046,'And Rebekah said to Isaac, I am weary of my life because of the daughters of Heth: if Jacob take a wife of the daughters of Heth, such as these which are of the daughters of the land, what good shall my life do me?'); -INSERT INTO t1(docid,words) VALUES(1028001,'And Isaac called Jacob, and blessed him, and charged him, and said unto him, Thou shalt not take a wife of the daughters of Canaan.'); -INSERT INTO t1(docid,words) VALUES(1028002,'Arise, go to Padanaram, to the house of Bethuel thy mother''s father; and take thee a wife from thence of the daughers of Laban thy mother''s brother.'); -INSERT INTO t1(docid,words) VALUES(1028003,'And God Almighty bless thee, and make thee fruitful, and multiply thee, that thou mayest be a multitude of people;'); -INSERT INTO t1(docid,words) VALUES(1028004,'And give thee the blessing of Abraham, to thee, and to thy seed with thee; that thou mayest inherit the land wherein thou art a stranger, which God gave unto Abraham.'); -INSERT INTO t1(docid,words) VALUES(1028005,'And Isaac sent away Jacob: and he went to Padanaram unto Laban, son of Bethuel the Syrian, the brother of Rebekah, Jacob''s and Esau''s mother.'); -INSERT INTO t1(docid,words) VALUES(1028006,'When Esau saw that Isaac had blessed Jacob, and sent him away to Padanaram, to take him a wife from thence; and that as he blessed him he gave him a charge, saying, Thou shalt not take a wife of the daughers of Canaan;'); -INSERT INTO t1(docid,words) VALUES(1028007,'And that Jacob obeyed his father and his mother, and was gone to Padanaram;'); -INSERT INTO t1(docid,words) VALUES(1028008,'And Esau seeing that the daughters of Canaan pleased not Isaac his father;'); -INSERT INTO t1(docid,words) VALUES(1028009,'Then went Esau unto Ishmael, and took unto the wives which he had Mahalath the daughter of Ishmael Abraham''s son, the sister of Nebajoth, to be his wife.'); -INSERT INTO t1(docid,words) VALUES(1028010,'And Jacob went out from Beersheba, and went toward Haran.'); -INSERT INTO t1(docid,words) VALUES(1028011,'And he lighted upon a certain place, and tarried there all night, because the sun was set; and he took of the stones of that place, and put them for his pillows, and lay down in that place to sleep.'); -INSERT INTO t1(docid,words) VALUES(1028012,'And he dreamed, and behold a ladder set up on the earth, and the top of it reached to heaven: and behold the angels of God ascending and descending on it.'); -INSERT INTO t1(docid,words) VALUES(1028013,'And, behold, the LORD stood above it, and said, I am the LORD God of Abraham thy father, and the God of Isaac: the land whereon thou liest, to thee will I give it, and to thy seed;'); -INSERT INTO t1(docid,words) VALUES(1028014,'And thy seed shall be as the dust of the earth, and thou shalt spread abroad to the west, and to the east, and to the north, and to the south: and in thee and in thy seed shall all the families of the earth be blessed.'); -INSERT INTO t1(docid,words) VALUES(1028015,'And, behold, I am with thee, and will keep thee in all places whither thou goest, and will bring thee again into this land; for I will not leave thee, until I have done that which I have spoken to thee of.'); -INSERT INTO t1(docid,words) VALUES(1028016,'And Jacob awaked out of his sleep, and he said, Surely the LORD is in this place; and I knew it not.'); -INSERT INTO t1(docid,words) VALUES(1028017,'And he was afraid, and said, How dreadful is this place! this is none other but the house of God, and this is the gate of heaven.'); -INSERT INTO t1(docid,words) VALUES(1028018,'And Jacob rose up early in the morning, and took the stone that he had put for his pillows, and set it up for a pillar, and poured oil upon the top of it.'); -INSERT INTO t1(docid,words) VALUES(1028019,'And he called the name of that place Bethel: but the name of that city was called Luz at the first.'); -INSERT INTO t1(docid,words) VALUES(1028020,'And Jacob vowed a vow, saying, If God will be with me, and will keep me in this way that I go, and will give me bread to eat, and raiment to put on,'); -INSERT INTO t1(docid,words) VALUES(1028021,'So that I come again to my father''s house in peace; then shall the LORD be my God:'); -INSERT INTO t1(docid,words) VALUES(1028022,'And this stone, which I have set for a pillar, shall be God''s house: and of all that thou shalt give me I will surely give the tenth unto thee.'); -INSERT INTO t1(docid,words) VALUES(1029001,'Then Jacob went on his journey, and came into the land of the people of the east.'); -INSERT INTO t1(docid,words) VALUES(1029002,'And he looked, and behold a well in the field, and, lo, there were three flocks of sheep lying by it; for out of that well they watered the flocks: and a great stone was upon the well''s mouth.'); -INSERT INTO t1(docid,words) VALUES(1029003,'And thither were all the flocks gathered: and they rolled the stone from the well''s mouth, and watered the sheep, and put the stone again upon the well''s mouth in his place.'); -INSERT INTO t1(docid,words) VALUES(1029004,'And Jacob said unto them, My brethren, whence be ye? And they said, Of Haran are we.'); -INSERT INTO t1(docid,words) VALUES(1029005,'And he said unto them, Know ye Laban the son of Nahor? And they said, We know him.'); -INSERT INTO t1(docid,words) VALUES(1029006,'And he said unto them, Is he well? And they said, He is well: and, behold, Rachel his daughter cometh with the sheep.'); -INSERT INTO t1(docid,words) VALUES(1029007,'And he said, Lo, it is yet high day, neither is it time that the cattle should be gathered together: water ye the sheep, and go and feed them.'); -INSERT INTO t1(docid,words) VALUES(1029008,'And they said, We cannot, until all the flocks be gathered together, and till they roll the stone from the well''s mouth; then we water the sheep.'); -INSERT INTO t1(docid,words) VALUES(1029009,'And while he yet spake with them, Rachel came with her father''s sheep; for she kept them.'); -INSERT INTO t1(docid,words) VALUES(1029010,'And it came to pass, when Jacob saw Rachel the daughter of Laban his mother''s brother, and the sheep of Laban his mother''s brother, that Jacob went near, and rolled the stone from the well''s mouth, and watered the flock of Laban his mother''s brother.'); -INSERT INTO t1(docid,words) VALUES(1029011,'And Jacob kissed Rachel, and lifted up his voice, and wept.'); -INSERT INTO t1(docid,words) VALUES(1029012,'And Jacob told Rachel that he was her father''s brother, and that he was Rebekah''s son: and she ran and told her father.'); -INSERT INTO t1(docid,words) VALUES(1029013,'And it came to pass, when Laban heard the tidings of Jacob his sister''s son, that he ran to meet him, and embraced him, and kissed him, and brought him to his house. And he told Laban all these things.'); -INSERT INTO t1(docid,words) VALUES(1029014,'And Laban said to him, Surely thou art my bone and my flesh. And he abode with him the space of a month.'); -INSERT INTO t1(docid,words) VALUES(1029015,'And Laban said unto Jacob, Because thou art my brother, shouldest thou therefore serve me for nought? tell me, what shall thy wages be?'); -INSERT INTO t1(docid,words) VALUES(1029016,'And Laban had two daughters: the name of the elder was Leah, and the name of the younger was Rachel.'); -INSERT INTO t1(docid,words) VALUES(1029017,'Leah was tender eyed; but Rachel was beautiful and well favoured.'); -INSERT INTO t1(docid,words) VALUES(1029018,'And Jacob loved Rachel; and said, I will serve thee seven years for Rachel thy younger daughter.'); -INSERT INTO t1(docid,words) VALUES(1029019,'And Laban said, It is better that I give her to thee, than that I should give her to another man: abide with me.'); -INSERT INTO t1(docid,words) VALUES(1029020,'And Jacob served seven years for Rachel; and they seemed unto him but a few days, for the love he had to her.'); -INSERT INTO t1(docid,words) VALUES(1029021,'And Jacob said unto Laban, Give me my wife, for my days are fulfilled, that I may go in unto her.'); -INSERT INTO t1(docid,words) VALUES(1029022,'And Laban gathered together all the men of the place, and made a feast.'); -INSERT INTO t1(docid,words) VALUES(1029023,'And it came to pass in the evening, that he took Leah his daughter, and brought her to him; and he went in unto her.'); -INSERT INTO t1(docid,words) VALUES(1029024,'And Laban gave unto his daughter Leah Zilpah his maid for an handmaid.'); -INSERT INTO t1(docid,words) VALUES(1029025,'And it came to pass, that in the morning, behold, it was Leah: and he said to Laban, What is this thou hast done unto me? did not I serve with thee for Rachel? wherefore then hast thou beguiled me?'); -INSERT INTO t1(docid,words) VALUES(1029026,'And Laban said, It must not be so done in our country, to give the younger before the firstborn.'); -INSERT INTO t1(docid,words) VALUES(1029027,'Fulfil her week, and we will give thee this also for the service which thou shalt serve with me yet seven other years.'); -INSERT INTO t1(docid,words) VALUES(1029028,'And Jacob did so, and fulfilled her week: and he gave him Rachel his daughter to wife also.'); -INSERT INTO t1(docid,words) VALUES(1029029,'And Laban gave to Rachel his daughter Bilhah his handmaid to be her maid.'); -INSERT INTO t1(docid,words) VALUES(1029030,'And he went in also unto Rachel, and he loved also Rachel more than Leah, and served with him yet seven other years.'); -INSERT INTO t1(docid,words) VALUES(1029031,'And when the LORD saw that Leah was hated, he opened her womb: but Rachel was barren.'); -INSERT INTO t1(docid,words) VALUES(1029032,'And Leah conceived, and bare a son, and she called his name Reuben: for she said, Surely the LORD hath looked upon my affliction; now therefore my husband will love me.'); -INSERT INTO t1(docid,words) VALUES(1029033,'And she conceived again, and bare a son; and said, Because the LORD hath heard I was hated, he hath therefore given me this son also: and she called his name Simeon.'); -INSERT INTO t1(docid,words) VALUES(1029034,'And she conceived again, and bare a son; and said, Now this time will my husband be joined unto me, because I have born him three sons: therefore was his name called Levi.'); -INSERT INTO t1(docid,words) VALUES(1029035,'And she conceived again, and bare a son: and she said, Now will I praise the LORD: therefore she called his name Judah; and left bearing.'); -INSERT INTO t1(docid,words) VALUES(1030001,'And when Rachel saw that she bare Jacob no children, Rachel envied her sister; and said unto Jacob, Give me children, or else I die.'); -INSERT INTO t1(docid,words) VALUES(1030002,'And Jacob''s anger was kindled against Rachel: and he said, Am I in God''s stead, who hath withheld from thee the fruit of the womb?'); -INSERT INTO t1(docid,words) VALUES(1030003,'And she said, Behold my maid Bilhah, go in unto her; and she shall bear upon my knees, that I may also have children by her.'); -INSERT INTO t1(docid,words) VALUES(1030004,'And she gave him Bilhah her handmaid to wife: and Jacob went in unto her.'); -INSERT INTO t1(docid,words) VALUES(1030005,'And Bilhah conceived, and bare Jacob a son.'); -INSERT INTO t1(docid,words) VALUES(1030006,'And Rachel said, God hath judged me, and hath also heard my voice, and hath given me a son: therefore called she his name Dan.'); -INSERT INTO t1(docid,words) VALUES(1030007,'And Bilhah Rachel''s maid conceived again, and bare Jacob a second son.'); -INSERT INTO t1(docid,words) VALUES(1030008,'And Rachel said, With great wrestlings have I wrestled with my sister, and I have prevailed: and she called his name Naphtali.'); -INSERT INTO t1(docid,words) VALUES(1030009,'When Leah saw that she had left bearing, she took Zilpah her maid, and gave her Jacob to wife.'); -INSERT INTO t1(docid,words) VALUES(1030010,'And Zilpah Leah''s maid bare Jacob a son.'); -INSERT INTO t1(docid,words) VALUES(1030011,'And Leah said, A troop cometh: and she called his name Gad.'); -INSERT INTO t1(docid,words) VALUES(1030012,'And Zilpah Leah''s maid bare Jacob a second son.'); -INSERT INTO t1(docid,words) VALUES(1030013,'And Leah said, Happy am I, for the daughters will call me blessed: and she called his name Asher.'); -INSERT INTO t1(docid,words) VALUES(1030014,'And Reuben went in the days of wheat harvest, and found mandrakes in the field, and brought them unto his mother Leah. Then Rachel said to Leah, Give me, I pray thee, of thy son''s mandrakes.'); -INSERT INTO t1(docid,words) VALUES(1030015,'And she said unto her, Is it a small matter that thou hast taken my husband? and wouldest thou take away my son''s mandrakes also? And Rachel said, Therefore he shall lie with thee to night for thy son''s mandrakes.'); -INSERT INTO t1(docid,words) VALUES(1030016,'And Jacob came out of the field in the evening, and Leah went out to meet him, and said, Thou must come in unto me; for surely I have hired thee with my son''s mandrakes. And he lay with her that night.'); -INSERT INTO t1(docid,words) VALUES(1030017,'And God hearkened unto Leah, and she conceived, and bare Jacob the fifth son.'); -INSERT INTO t1(docid,words) VALUES(1030018,'And Leah said, God hath given me my hire, because I have given my maiden to my husband: and she called his name Issachar.'); -INSERT INTO t1(docid,words) VALUES(1030019,'And Leah conceived again, and bare Jacob the sixth son.'); -INSERT INTO t1(docid,words) VALUES(1030020,'And Leah said, God hath endued me with a good dowry; now will my husband dwell with me, because I have born him six sons: and she called his name Zebulun.'); -INSERT INTO t1(docid,words) VALUES(1030021,'And afterwards she bare a daughter, and called her name Dinah.'); -INSERT INTO t1(docid,words) VALUES(1030022,'And God remembered Rachel, and God hearkened to her, and opened her womb.'); -INSERT INTO t1(docid,words) VALUES(1030023,'And she conceived, and bare a son; and said, God hath taken away my reproach:'); -INSERT INTO t1(docid,words) VALUES(1030024,'And she called his name Joseph; and said, The LORD shall add to me another son.'); -INSERT INTO t1(docid,words) VALUES(1030025,'And it came to pass, when Rachel had born Joseph, that Jacob said unto Laban, Send me away, that I may go unto mine own place, and to my country.'); -INSERT INTO t1(docid,words) VALUES(1030026,'Give me my wives and my children, for whom I have served thee, and let me go: for thou knowest my service which I have done thee.'); -INSERT INTO t1(docid,words) VALUES(1030027,'And Laban said unto him, I pray thee, if I have found favour in thine eyes, tarry: for I have learned by experience that the LORD hath blessed me for thy sake.'); -INSERT INTO t1(docid,words) VALUES(1030028,'And he said, Appoint me thy wages, and I will give it.'); -INSERT INTO t1(docid,words) VALUES(1030029,'And he said unto him, Thou knowest how I have served thee, and how thy cattle was with me.'); -INSERT INTO t1(docid,words) VALUES(1030030,'For it was little which thou hadst before I came, and it is now increased unto a multitude; and the LORD hath blessed thee since my coming: and now when shall I provide for mine own house also?'); -INSERT INTO t1(docid,words) VALUES(1030031,'And he said, What shall I give thee? And Jacob said, Thou shalt not give me any thing: if thou wilt do this thing for me, I will again feed and keep thy flock.'); -INSERT INTO t1(docid,words) VALUES(1030032,'I will pass through all thy flock to day, removing from thence all the speckled and spotted cattle, and all the brown cattle among the sheep, and the spotted and speckled among the goats: and of such shall be my hire.'); -INSERT INTO t1(docid,words) VALUES(1030033,'So shall my righteousness answer for me in time to come, when it shall come for my hire before thy face: every one that is not speckled and spotted among the goats, and brown among the sheep, that shall be counted stolen with me.'); -INSERT INTO t1(docid,words) VALUES(1030034,'And Laban said, Behold, I would it might be according to thy word.'); -INSERT INTO t1(docid,words) VALUES(1030035,'And he removed that day the he goats that were ringstraked and spotted, and all the she goats that were speckled and spotted, and every one that had some white in it, and all the brown among the sheep, and gave them into the hand of his sons.'); -INSERT INTO t1(docid,words) VALUES(1030036,'And he set three days'' journey betwixt himself and Jacob: and Jacob fed the rest of Laban''s flocks.'); -INSERT INTO t1(docid,words) VALUES(1030037,'And Jacob took him rods of green poplar, and of the hazel and chesnut tree; and pilled white strakes in them, and made the white appear which was in the rods.'); -INSERT INTO t1(docid,words) VALUES(1030038,'And he set the rods which he had pilled before the flocks in the gutters in the watering troughs when the flocks came to drink, that they should conceive when they came to drink.'); -INSERT INTO t1(docid,words) VALUES(1030039,'And the flocks conceived before the rods, and brought forth cattle ringstraked, speckled, and spotted.'); -INSERT INTO t1(docid,words) VALUES(1030040,'And Jacob did separate the lambs, and set the faces of the flocks toward the ringstraked, and all the brown in the flock of Laban; and he put his own flocks by themselves, and put them not unto Laban''s cattle.'); -INSERT INTO t1(docid,words) VALUES(1030041,'And it came to pass, whensoever the stronger cattle did conceive, that Jacob laid the rods before the eyes of the cattle in the gutters, that they might conceive among the rods.'); -INSERT INTO t1(docid,words) VALUES(1030042,'But when the cattle were feeble, he put them not in: so the feebler were Laban''s, and the stronger Jacob''s.'); -INSERT INTO t1(docid,words) VALUES(1030043,'And the man increased exceedingly, and had much cattle, and maidservants, and menservants, and camels, and asses.'); -INSERT INTO t1(docid,words) VALUES(1031001,'And he heard the words of Laban''s sons, saying, Jacob hath taken away all that was our father''s; and of that which was our father''s hath he gotten all this glory.'); -INSERT INTO t1(docid,words) VALUES(1031002,'And Jacob beheld the countenance of Laban, and, behold, it was not toward him as before.'); -INSERT INTO t1(docid,words) VALUES(1031003,'And the LORD said unto Jacob, Return unto the land of thy fathers, and to thy kindred; and I will be with thee.'); -INSERT INTO t1(docid,words) VALUES(1031004,'And Jacob sent and called Rachel and Leah to the field unto his flock,'); -INSERT INTO t1(docid,words) VALUES(1031005,'And said unto them, I see your father''s countenance, that it is not toward me as before; but the God of my father hath been with me.'); -INSERT INTO t1(docid,words) VALUES(1031006,'And ye know that with all my power I have served your father.'); -INSERT INTO t1(docid,words) VALUES(1031007,'And your father hath deceived me, and changed my wages ten times; but God suffered him not to hurt me.'); -INSERT INTO t1(docid,words) VALUES(1031008,'If he said thus, The speckled shall be thy wages; then all the cattle bare speckled: and if he said thus, The ringstraked shall be thy hire; then bare all the cattle ringstraked.'); -INSERT INTO t1(docid,words) VALUES(1031009,'Thus God hath taken away the cattle of your father, and given them to me.'); -INSERT INTO t1(docid,words) VALUES(1031010,'And it came to pass at the time that the cattle conceived, that I lifted up mine eyes, and saw in a dream, and, behold, the rams which leaped upon the cattle were ringstraked, speckled, and grisled.'); -INSERT INTO t1(docid,words) VALUES(1031011,'And the angel of God spake unto me in a dream, saying, Jacob: And I said, Here am I.'); -INSERT INTO t1(docid,words) VALUES(1031012,'And he said, Lift up now thine eyes, and see, all the rams which leap upon the cattle are ringstraked, speckled, and grisled: for I have seen all that Laban doeth unto thee.'); -INSERT INTO t1(docid,words) VALUES(1031013,'I am the God of Bethel, where thou anointedst the pillar, and where thou vowedst a vow unto me: now arise, get thee out from this land, and return unto the land of thy kindred.'); -INSERT INTO t1(docid,words) VALUES(1031014,'And Rachel and Leah answered and said unto him, Is there yet any portion or inheritance for us in our father''s house?'); -INSERT INTO t1(docid,words) VALUES(1031015,'Are we not counted of him strangers? for he hath sold us, and hath quite devoured also our money.'); -INSERT INTO t1(docid,words) VALUES(1031016,'For all the riches which God hath taken from our father, that is ours, and our children''s: now then, whatsoever God hath said unto thee, do.'); -INSERT INTO t1(docid,words) VALUES(1031017,'Then Jacob rose up, and set his sons and his wives upon camels;'); -INSERT INTO t1(docid,words) VALUES(1031018,'And he carried away all his cattle, and all his goods which he had gotten, the cattle of his getting, which he had gotten in Padanaram, for to go to Isaac his father in the land of Canaan.'); -INSERT INTO t1(docid,words) VALUES(1031019,'And Laban went to shear his sheep: and Rachel had stolen the images that were her father''s.'); -INSERT INTO t1(docid,words) VALUES(1031020,'And Jacob stole away unawares to Laban the Syrian, in that he told him not that he fled.'); -INSERT INTO t1(docid,words) VALUES(1031021,'So he fled with all that he had; and he rose up, and passed over the river, and set his face toward the mount Gilead.'); -INSERT INTO t1(docid,words) VALUES(1031022,'And it was told Laban on the third day that Jacob was fled.'); -INSERT INTO t1(docid,words) VALUES(1031023,'And he took his brethren with him, and pursued after him seven days'' journey; and they overtook him in the mount Gilead.'); -INSERT INTO t1(docid,words) VALUES(1031024,'And God came to Laban the Syrian in a dream by night, and said unto him, Take heed that thou speak not to Jacob either good or bad.'); -INSERT INTO t1(docid,words) VALUES(1031025,'Then Laban overtook Jacob. Now Jacob had pitched his tent in the mount: and Laban with his brethren pitched in the mount of Gilead.'); -INSERT INTO t1(docid,words) VALUES(1031026,'And Laban said to Jacob, What hast thou done, that thou hast stolen away unawares to me, and carried away my daughters, as captives taken with the sword?'); -INSERT INTO t1(docid,words) VALUES(1031027,'Wherefore didst thou flee away secretly, and steal away from me; and didst not tell me, that I might have sent thee away with mirth, and with songs, with tabret, and with harp?'); -INSERT INTO t1(docid,words) VALUES(1031028,'And hast not suffered me to kiss my sons and my daughters? thou hast now done foolishly in so doing.'); -INSERT INTO t1(docid,words) VALUES(1031029,'It is in the power of my hand to do you hurt: but the God of your father spake unto me yesternight, saying, Take thou heed that thou speak not to Jacob either good or bad.'); -INSERT INTO t1(docid,words) VALUES(1031030,'And now, though thou wouldest needs be gone, because thou sore longedst after thy father''s house, yet wherefore hast thou stolen my gods?'); -INSERT INTO t1(docid,words) VALUES(1031031,'And Jacob answered and said to Laban, Because I was afraid: for I said, Peradventure thou wouldest take by force thy daughters from me.'); -INSERT INTO t1(docid,words) VALUES(1031032,'With whomsoever thou findest thy gods, let him not live: before our brethren discern thou what is thine with me, and take it to thee. For Jacob knew not that Rachel had stolen them.'); -INSERT INTO t1(docid,words) VALUES(1031033,'And Laban went into Jacob''s tent, and into Leah''s tent, and into the two maidservants'' tents; but he found them not. Then went he out of Leah''s tent, and entered into Rachel''s tent.'); -INSERT INTO t1(docid,words) VALUES(1031034,'Now Rachel had taken the images, and put them in the camel''s furniture, and sat upon them. And Laban searched all the tent, but found them not.'); -INSERT INTO t1(docid,words) VALUES(1031035,'And she said to her father, Let it not displease my lord that I cannot rise up before thee; for the custom of women is upon me. And he searched but found not the images.'); -INSERT INTO t1(docid,words) VALUES(1031036,'And Jacob was wroth, and chode with Laban: and Jacob answered and said to Laban, What is my trespass? what is my sin, that thou hast so hotly pursued after me?'); -INSERT INTO t1(docid,words) VALUES(1031037,'Whereas thou hast searched all my stuff, what hast thou found of all thy household stuff? set it here before my brethren and thy brethren, that they may judge betwixt us both.'); -INSERT INTO t1(docid,words) VALUES(1031038,'This twenty years have I been with thee; thy ewes and thy she goats have not cast their young, and the rams of thy flock have I not eaten.'); -INSERT INTO t1(docid,words) VALUES(1031039,'That which was torn of beasts I brought not unto thee; I bare the loss of it; of my hand didst thou require it, whether stolen by day, or stolen by night.'); -INSERT INTO t1(docid,words) VALUES(1031040,'Thus I was; in the day the drought consumed me, and the frost by night; and my sleep departed from mine eyes.'); -INSERT INTO t1(docid,words) VALUES(1031041,'Thus have I been twenty years in thy house; I served thee fourteen years for thy two daughters, and six years for thy cattle: and thou hast changed my wages ten times.'); -INSERT INTO t1(docid,words) VALUES(1031042,'Except the God of my father, the God of Abraham, and the fear of Isaac, had been with me, surely thou hadst sent me away now empty. God hath seen mine affliction and the labour of my hands, and rebuked thee yesternight.'); -INSERT INTO t1(docid,words) VALUES(1031043,'And Laban answered and said unto Jacob, These daughters are my daughters, and these children are my children, and these cattle are my cattle, and all that thou seest is mine: and what can I do this day unto these my daughters, or unto their children which they have born?'); -INSERT INTO t1(docid,words) VALUES(1031044,'Now therefore come thou, let us make a covenant, I and thou; and let it be for a witness between me and thee.'); -INSERT INTO t1(docid,words) VALUES(1031045,'And Jacob took a stone, and set it up for a pillar.'); -INSERT INTO t1(docid,words) VALUES(1031046,'And Jacob said unto his brethren, Gather stones; and they took stones, and made an heap: and they did eat there upon the heap.'); -INSERT INTO t1(docid,words) VALUES(1031047,'And Laban called it Jegarsahadutha: but Jacob called it Galeed.'); -INSERT INTO t1(docid,words) VALUES(1031048,'And Laban said, This heap is a witness between me and thee this day. Therefore was the name of it called Galeed;'); -INSERT INTO t1(docid,words) VALUES(1031049,'And Mizpah; for he said, The LORD watch between me and thee, when we are absent one from another.'); -INSERT INTO t1(docid,words) VALUES(1031050,'If thou shalt afflict my daughters, or if thou shalt take other wives beside my daughters, no man is with us; see, God is witness betwixt me and thee.'); -INSERT INTO t1(docid,words) VALUES(1031051,'And Laban said to Jacob, Behold this heap, and behold this pillar, which I have cast betwixt me and thee:'); -INSERT INTO t1(docid,words) VALUES(1031052,'This heap be witness, and this pillar be witness, that I will not pass over this heap to thee, and that thou shalt not pass over this heap and this pillar unto me, for harm.'); -INSERT INTO t1(docid,words) VALUES(1031053,'The God of Abraham, and the God of Nahor, the God of their father, judge betwixt us. And Jacob sware by the fear of his father Isaac.'); -INSERT INTO t1(docid,words) VALUES(1031054,'Then Jacob offered sacrifice upon the mount, and called his brethren to eat bread: and they did eat bread, and tarried all night in the mount.'); -INSERT INTO t1(docid,words) VALUES(1031055,'And early in the morning Laban rose up, and kissed his sons and his daughters, and blessed them: and Laban departed, and returned unto his place.'); -INSERT INTO t1(docid,words) VALUES(1032001,'And Jacob went on his way, and the angels of God met him.'); -INSERT INTO t1(docid,words) VALUES(1032002,'And when Jacob saw them, he said, This is God''s host: and he called the name of that place Mahanaim.'); -INSERT INTO t1(docid,words) VALUES(1032003,'And Jacob sent messengers before him to Esau his brother unto the land of Seir, the country of Edom.'); -INSERT INTO t1(docid,words) VALUES(1032004,'And he commanded them, saying, Thus shall ye speak unto my lord Esau; Thy servant Jacob saith thus, I have sojourned with Laban, and stayed there until now:'); -INSERT INTO t1(docid,words) VALUES(1032005,'And I have oxen, and asses, flocks, and menservants, and womenservants: and I have sent to tell my lord, that I may find grace in thy sight.'); -INSERT INTO t1(docid,words) VALUES(1032006,'And the messengers returned to Jacob, saying, We came to thy brother Esau, and also he cometh to meet thee, and four hundred men with him.'); -INSERT INTO t1(docid,words) VALUES(1032007,'Then Jacob was greatly afraid and distressed: and he divided the people that was with him, and the flocks, and herds, and the camels, into two bands;'); -INSERT INTO t1(docid,words) VALUES(1032008,'And said, If Esau come to the one company, and smite it, then the other company which is left shall escape.'); -INSERT INTO t1(docid,words) VALUES(1032009,'And Jacob said, O God of my father Abraham, and God of my father Isaac, the LORD which saidst unto me, Return unto thy country, and to thy kindred, and I will deal well with thee:'); -INSERT INTO t1(docid,words) VALUES(1032010,'I am not worthy of the least of all the mercies, and of all the truth, which thou hast shewed unto thy servant; for with my staff I passed over this Jordan; and now I am become two bands.'); -INSERT INTO t1(docid,words) VALUES(1032011,'Deliver me, I pray thee, from the hand of my brother, from the hand of Esau: for I fear him, lest he will come and smite me, and the mother with the children.'); -INSERT INTO t1(docid,words) VALUES(1032012,'And thou saidst, I will surely do thee good, and make thy seed as the sand of the sea, which cannot be numbered for multitude.'); -INSERT INTO t1(docid,words) VALUES(1032013,'And he lodged there that same night; and took of that which came to his hand a present for Esau his brother;'); -INSERT INTO t1(docid,words) VALUES(1032014,'Two hundred she goats, and twenty he goats, two hundred ewes, and twenty rams,'); -INSERT INTO t1(docid,words) VALUES(1032015,'Thirty milch camels with their colts, forty kine, and ten bulls, twenty she asses, and ten foals.'); -INSERT INTO t1(docid,words) VALUES(1032016,'And he delivered them into the hand of his servants, every drove by themselves; and said unto his servants, Pass over before me, and put a space betwixt drove and drove.'); -INSERT INTO t1(docid,words) VALUES(1032017,'And he commanded the foremost, saying, When Esau my brother meeteth thee, and asketh thee, saying, Whose art thou? and whither goest thou? and whose are these before thee?'); -INSERT INTO t1(docid,words) VALUES(1032018,'Then thou shalt say, They be thy servant Jacob''s; it is a present sent unto my lord Esau: and, behold, also he is behind us.'); -INSERT INTO t1(docid,words) VALUES(1032019,'And so commanded he the second, and the third, and all that followed the droves, saying, On this manner shall ye speak unto Esau, when ye find him.'); -INSERT INTO t1(docid,words) VALUES(1032020,'And say ye moreover, Behold, thy servant Jacob is behind us. For he said, I will appease him with the present that goeth before me, and afterward I will see his face; peradventure he will accept of me.'); -INSERT INTO t1(docid,words) VALUES(1032021,'So went the present over before him: and himself lodged that night in the company.'); -INSERT INTO t1(docid,words) VALUES(1032022,'And he rose up that night, and took his two wives, and his two womenservants, and his eleven sons, and passed over the ford Jabbok.'); -INSERT INTO t1(docid,words) VALUES(1032023,'And he took them, and sent them over the brook, and sent over that he had.'); -INSERT INTO t1(docid,words) VALUES(1032024,'And Jacob was left alone; and there wrestled a man with him until the breaking of the day.'); -INSERT INTO t1(docid,words) VALUES(1032025,'And when he saw that he prevailed not against him, he touched the hollow of his thigh; and the hollow of Jacob''s thigh was out of joint, as he wrestled with him.'); -INSERT INTO t1(docid,words) VALUES(1032026,'And he said, Let me go, for the day breaketh. And he said, I will not let thee go, except thou bless me.'); -INSERT INTO t1(docid,words) VALUES(1032027,'And he said unto him, What is thy name? And he said, Jacob.'); -INSERT INTO t1(docid,words) VALUES(1032028,'And he said, Thy name shall be called no more Jacob, but Israel: for as a prince hast thou power with God and with men, and hast prevailed.'); -INSERT INTO t1(docid,words) VALUES(1032029,'And Jacob asked him, and said, Tell me, I pray thee, thy name. And he said, Wherefore is it that thou dost ask after my name? And he blessed him there.'); -INSERT INTO t1(docid,words) VALUES(1032030,'And Jacob called the name of the place Peniel: for I have seen God face to face, and my life is preserved.'); -INSERT INTO t1(docid,words) VALUES(1032031,'And as he passed over Penuel the sun rose upon him, and he halted upon his thigh.'); -INSERT INTO t1(docid,words) VALUES(1032032,'Therefore the children of Israel eat not of the sinew which shrank, which is upon the hollow of the thigh, unto this day: because he touched the hollow of Jacob''s thigh in the sinew that shrank.'); -INSERT INTO t1(docid,words) VALUES(1033001,'And Jacob lifted up his eyes, and looked, and, behold, Esau came, and with him four hundred men. And he divided the children unto Leah, and unto Rachel, and unto the two handmaids.'); -INSERT INTO t1(docid,words) VALUES(1033002,'And he put the handmaids and their children foremost, and Leah and her children after, and Rachel and Joseph hindermost.'); -INSERT INTO t1(docid,words) VALUES(1033003,'And he passed over before them, and bowed himself to the ground seven times, until he came near to his brother.'); -INSERT INTO t1(docid,words) VALUES(1033004,'And Esau ran to meet him, and embraced him, and fell on his neck, and kissed him: and they wept.'); -INSERT INTO t1(docid,words) VALUES(1033005,'And he lifted up his eyes, and saw the women and the children; and said, Who are those with thee? And he said, The children which God hath graciously given thy servant.'); -INSERT INTO t1(docid,words) VALUES(1033006,'Then the handmaidens came near, they and their children, and they bowed themselves.'); -INSERT INTO t1(docid,words) VALUES(1033007,'And Leah also with her children came near, and bowed themselves: and after came Joseph near and Rachel, and they bowed themselves.'); -INSERT INTO t1(docid,words) VALUES(1033008,'And he said, What meanest thou by all this drove which I met? And he said, These are to find grace in the sight of my lord.'); -INSERT INTO t1(docid,words) VALUES(1033009,'And Esau said, I have enough, my brother; keep that thou hast unto thyself.'); -INSERT INTO t1(docid,words) VALUES(1033010,'And Jacob said, Nay, I pray thee, if now I have found grace in thy sight, then receive my present at my hand: for therefore I have seen thy face, as though I had seen the face of God, and thou wast pleased with me.'); -INSERT INTO t1(docid,words) VALUES(1033011,'Take, I pray thee, my blessing that is brought to thee; because God hath dealt graciously with me, and because I have enough. And he urged him, and he took it.'); -INSERT INTO t1(docid,words) VALUES(1033012,'And he said, Let us take our journey, and let us go, and I will go before thee.'); -INSERT INTO t1(docid,words) VALUES(1033013,'And he said unto him, My lord knoweth that the children are tender, and the flocks and herds with young are with me: and if men should overdrive them one day, all the flock will die.'); -INSERT INTO t1(docid,words) VALUES(1033014,'Let my lord, I pray thee, pass over before his servant: and I will lead on softly, according as the cattle that goeth before me and the children be able to endure, until I come unto my lord unto Seir.'); -INSERT INTO t1(docid,words) VALUES(1033015,'And Esau said, Let me now leave with thee some of the folk that are with me. And he said, What needeth it? let me find grace in the sight of my lord.'); -INSERT INTO t1(docid,words) VALUES(1033016,'So Esau returned that day on his way unto Seir.'); -INSERT INTO t1(docid,words) VALUES(1033017,'And Jacob journeyed to Succoth, and built him an house, and made booths for his cattle: therefore the name of the place is called Succoth.'); -INSERT INTO t1(docid,words) VALUES(1033018,'And Jacob came to Shalem, a city of Shechem, which is in the land of Canaan, when he came from Padanaram; and pitched his tent before the city.'); -INSERT INTO t1(docid,words) VALUES(1033019,'And he bought a parcel of a field, where he had spread his tent, at the hand of the children of Hamor, Shechem''s father, for an hundred pieces of money.'); -INSERT INTO t1(docid,words) VALUES(1033020,'And he erected there an altar, and called it EleloheIsrael.'); -INSERT INTO t1(docid,words) VALUES(1034001,'And Dinah the daughter of Leah, which she bare unto Jacob, went out to see the daughters of the land.'); -INSERT INTO t1(docid,words) VALUES(1034002,'And when Shechem the son of Hamor the Hivite, prince of the country, saw her, he took her, and lay with her, and defiled her.'); -INSERT INTO t1(docid,words) VALUES(1034003,'And his soul clave unto Dinah the daughter of Jacob, and he loved the damsel, and spake kindly unto the damsel.'); -INSERT INTO t1(docid,words) VALUES(1034004,'And Shechem spake unto his father Hamor, saying, Get me this damsel to wife.'); -INSERT INTO t1(docid,words) VALUES(1034005,'And Jacob heard that he had defiled Dinah his daughter: now his sons were with his cattle in the field: and Jacob held his peace until they were come.'); -INSERT INTO t1(docid,words) VALUES(1034006,'And Hamor the father of Shechem went out unto Jacob to commune with him.'); -INSERT INTO t1(docid,words) VALUES(1034007,'And the sons of Jacob came out of the field when they heard it: and the men were grieved, and they were very wroth, because he had wrought folly in Israel in lying with Jacob''s daughter: which thing ought not to be done.'); -INSERT INTO t1(docid,words) VALUES(1034008,'And Hamor communed with them, saying, The soul of my son Shechem longeth for your daughter: I pray you give her him to wife.'); -INSERT INTO t1(docid,words) VALUES(1034009,'And make ye marriages with us, and give your daughters unto us, and take our daughters unto you.'); -INSERT INTO t1(docid,words) VALUES(1034010,'And ye shall dwell with us: and the land shall be before you; dwell and trade ye therein, and get you possessions therein.'); -INSERT INTO t1(docid,words) VALUES(1034011,'And Shechem said unto her father and unto her brethren, Let me find grace in your eyes, and what ye shall say unto me I will give.'); -INSERT INTO t1(docid,words) VALUES(1034012,'Ask me never so much dowry and gift, and I will give according as ye shall say unto me: but give me the damsel to wife.'); -INSERT INTO t1(docid,words) VALUES(1034013,'And the sons of Jacob answered Shechem and Hamor his father deceitfully, and said, because he had defiled Dinah their sister:'); -INSERT INTO t1(docid,words) VALUES(1034014,'And they said unto them, We cannot do this thing, to give our sister to one that is uncircumcised; for that were a reproach unto us:'); -INSERT INTO t1(docid,words) VALUES(1034015,'But in this will we consent unto you: If ye will be as we be, that every male of you be circumcised;'); -INSERT INTO t1(docid,words) VALUES(1034016,'Then will we give our daughters unto you, and we will take your daughters to us, and we will dwell with you, and we will become one people.'); -INSERT INTO t1(docid,words) VALUES(1034017,'But if ye will not hearken unto us, to be circumcised; then will we take our daughter, and we will be gone.'); -INSERT INTO t1(docid,words) VALUES(1034018,'And their words pleased Hamor, and Shechem Hamor''s son.'); -INSERT INTO t1(docid,words) VALUES(1034019,'And the young man deferred not to do the thing, because he had delight in Jacob''s daughter: and he was more honourable than all the house of his father.'); -INSERT INTO t1(docid,words) VALUES(1034020,'And Hamor and Shechem his son came unto the gate of their city, and communed with the men of their city, saying,'); -INSERT INTO t1(docid,words) VALUES(1034021,'These men are peaceable with us; therefore let them dwell in the land, and trade therein; for the land, behold, it is large enough for them; let us take their daughters to us for wives, and let us give them our daughters.'); -INSERT INTO t1(docid,words) VALUES(1034022,'Only herein will the men consent unto us for to dwell with us, to be one people, if every male among us be circumcised, as they are circumcised.'); -INSERT INTO t1(docid,words) VALUES(1034023,'Shall not their cattle and their substance and every beast of their''s be our''s? only let us consent unto them, and they will dwell with us.'); -INSERT INTO t1(docid,words) VALUES(1034024,'And unto Hamor and unto Shechem his son hearkened all that went out of the gate of his city; and every male was circumcised, all that went out of the gate of his city.'); -INSERT INTO t1(docid,words) VALUES(1034025,'And it came to pass on the third day, when they were sore, that two of the sons of Jacob, Simeon and Levi, Dinah''s brethren, took each man his sword, and came upon the city boldly, and slew all the males.'); -INSERT INTO t1(docid,words) VALUES(1034026,'And they slew Hamor and Shechem his son with the edge of the sword, and took Dinah out of Shechem''s house, and went out.'); -INSERT INTO t1(docid,words) VALUES(1034027,'The sons of Jacob came upon the slain, and spoiled the city, because they had defiled their sister.'); -INSERT INTO t1(docid,words) VALUES(1034028,'They took their sheep, and their oxen, and their asses, and that which was in the city, and that which was in the field,'); -INSERT INTO t1(docid,words) VALUES(1034029,'And all their wealth, and all their little ones, and their wives took they captive, and spoiled even all that was in the house.'); -INSERT INTO t1(docid,words) VALUES(1034030,'And Jacob said to Simeon and Levi, Ye have troubled me to make me to stink among the inhabitants of the land, among the Canaanites and the Perizzites: and I being few in number, they shall gather themselves together against me, and slay me; and I shall be destroyed, I and my house.'); -INSERT INTO t1(docid,words) VALUES(1034031,'And they said, Should he deal with our sister as with an harlot?'); -INSERT INTO t1(docid,words) VALUES(1035001,'And God said unto Jacob, Arise, go up to Bethel, and dwell there: and make there an altar unto God, that appeared unto thee when thou fleddest from the face of Esau thy brother.'); -INSERT INTO t1(docid,words) VALUES(1035002,'Then Jacob said unto his household, and to all that were with him, Put away the strange gods that are among you, and be clean, and change your garments:'); -INSERT INTO t1(docid,words) VALUES(1035003,'And let us arise, and go up to Bethel; and I will make there an altar unto God, who answered me in the day of my distress, and was with me in the way which I went.'); -INSERT INTO t1(docid,words) VALUES(1035004,'And they gave unto Jacob all the strange gods which were in their hand, and all their earrings which were in their ears; and Jacob hid them under the oak which was by Shechem.'); -INSERT INTO t1(docid,words) VALUES(1035005,'And they journeyed: and the terror of God was upon the cities that were round about them, and they did not pursue after the sons of Jacob.'); -INSERT INTO t1(docid,words) VALUES(1035006,'So Jacob came to Luz, which is in the land of Canaan, that is, Bethel, he and all the people that were with him.'); -INSERT INTO t1(docid,words) VALUES(1035007,'And he built there an altar, and called the place Elbethel: because there God appeared unto him, when he fled from the face of his brother.'); -INSERT INTO t1(docid,words) VALUES(1035008,'But Deborah Rebekah''s nurse died, and she was buried beneath Bethel under an oak: and the name of it was called Allonbachuth.'); -INSERT INTO t1(docid,words) VALUES(1035009,'And God appeared unto Jacob again, when he came out of Padanaram, and blessed him.'); -INSERT INTO t1(docid,words) VALUES(1035010,'And God said unto him, Thy name is Jacob: thy name shall not be called any more Jacob, but Israel shall be thy name: and he called his name Israel.'); -INSERT INTO t1(docid,words) VALUES(1035011,'And God said unto him, I am God Almighty: be fruitful and multiply; a nation and a company of nations shall be of thee, and kings shall come out of thy loins;'); -INSERT INTO t1(docid,words) VALUES(1035012,'And the land which I gave Abraham and Isaac, to thee I will give it, and to thy seed after thee will I give the land.'); -INSERT INTO t1(docid,words) VALUES(1035013,'And God went up from him in the place where he talked with him.'); -INSERT INTO t1(docid,words) VALUES(1035014,'And Jacob set up a pillar in the place where he talked with him, even a pillar of stone: and he poured a drink offering thereon, and he poured oil thereon.'); -INSERT INTO t1(docid,words) VALUES(1035015,'And Jacob called the name of the place where God spake with him, Bethel.'); -INSERT INTO t1(docid,words) VALUES(1035016,'And they journeyed from Bethel; and there was but a little way to come to Ephrath: and Rachel travailed, and she had hard labour.'); -INSERT INTO t1(docid,words) VALUES(1035017,'And it came to pass, when she was in hard labour, that the midwife said unto her, Fear not; thou shalt have this son also.'); -INSERT INTO t1(docid,words) VALUES(1035018,'And it came to pass, as her soul was in departing, (for she died) that she called his name Benoni: but his father called him Benjamin.'); -INSERT INTO t1(docid,words) VALUES(1035019,'And Rachel died, and was buried in the way to Ephrath, which is Bethlehem.'); -INSERT INTO t1(docid,words) VALUES(1035020,'And Jacob set a pillar upon her grave: that is the pillar of Rachel''s grave unto this day.'); -INSERT INTO t1(docid,words) VALUES(1035021,'And Israel journeyed, and spread his tent beyond the tower of Edar.'); -INSERT INTO t1(docid,words) VALUES(1035022,'And it came to pass, when Israel dwelt in that land, that Reuben went and lay with Bilhah his father''s concubine: and Israel heard it. Now the sons of Jacob were twelve:'); -INSERT INTO t1(docid,words) VALUES(1035023,'The sons of Leah; Reuben, Jacob''s firstborn, and Simeon, and Levi, and Judah, and Issachar, and Zebulun:'); -INSERT INTO t1(docid,words) VALUES(1035024,'The sons of Rachel; Joseph, and Benjamin:'); -INSERT INTO t1(docid,words) VALUES(1035025,'And the sons of Bilhah, Rachel''s handmaid; Dan, and Naphtali:'); -INSERT INTO t1(docid,words) VALUES(1035026,'And the sons of Zilpah, Leah''s handmaid: Gad, and Asher: these are the sons of Jacob, which were born to him in Padanaram.'); -INSERT INTO t1(docid,words) VALUES(1035027,'And Jacob came unto Isaac his father unto Mamre, unto the city of Arbah, which is Hebron, where Abraham and Isaac sojourned.'); -INSERT INTO t1(docid,words) VALUES(1035028,'And the days of Isaac were an hundred and fourscore years.'); -INSERT INTO t1(docid,words) VALUES(1035029,'And Isaac gave up the ghost, and died, and was gathered unto his people, being old and full of days: and his sons Esau and Jacob buried him.'); -INSERT INTO t1(docid,words) VALUES(1036001,'Now these are the generations of Esau, who is Edom.'); -INSERT INTO t1(docid,words) VALUES(1036002,'Esau took his wives of the daughters of Canaan; Adah the daughter of Elon the Hittite, and Aholibamah the daughter of Anah the daughter of Zibeon the Hivite;'); -INSERT INTO t1(docid,words) VALUES(1036003,'And Bashemath Ishmael''s daughter, sister of Nebajoth.'); -INSERT INTO t1(docid,words) VALUES(1036004,'And Adah bare to Esau Eliphaz; and Bashemath bare Reuel;'); -INSERT INTO t1(docid,words) VALUES(1036005,'And Aholibamah bare Jeush, and Jaalam, and Korah: these are the sons of Esau, which were born unto him in the land of Canaan.'); -INSERT INTO t1(docid,words) VALUES(1036006,'And Esau took his wives, and his sons, and his daughters, and all the persons of his house, and his cattle, and all his beasts, and all his substance, which he had got in the land of Canaan; and went into the country from the face of his brother Jacob.'); -INSERT INTO t1(docid,words) VALUES(1036007,'For their riches were more than that they might dwell together; and the land wherein they were strangers could not bear them because of their cattle.'); -INSERT INTO t1(docid,words) VALUES(1036008,'Thus dwelt Esau in mount Seir: Esau is Edom.'); -INSERT INTO t1(docid,words) VALUES(1036009,'And these are the generations of Esau the father of the Edomites in mount Seir:'); -INSERT INTO t1(docid,words) VALUES(1036010,'These are the names of Esau''s sons; Eliphaz the son of Adah the wife of Esau, Reuel the son of Bashemath the wife of Esau.'); -INSERT INTO t1(docid,words) VALUES(1036011,'And the sons of Eliphaz were Teman, Omar, Zepho, and Gatam, and Kenaz.'); -INSERT INTO t1(docid,words) VALUES(1036012,'And Timna was concubine to Eliphaz Esau''s son; and she bare to Eliphaz Amalek: these were the sons of Adah Esau''s wife.'); -INSERT INTO t1(docid,words) VALUES(1036013,'And these are the sons of Reuel; Nahath, and Zerah, Shammah, and Mizzah: these were the sons of Bashemath Esau''s wife.'); -INSERT INTO t1(docid,words) VALUES(1036014,'And these were the sons of Aholibamah, the daughter of Anah the daughter of Zibeon, Esau''s wife: and she bare to Esau Jeush, and Jaalam, and Korah.'); -INSERT INTO t1(docid,words) VALUES(1036015,'These were dukes of the sons of Esau: the sons of Eliphaz the firstborn son of Esau; duke Teman, duke Omar, duke Zepho, duke Kenaz,'); -INSERT INTO t1(docid,words) VALUES(1036016,'Duke Korah, duke Gatam, and duke Amalek: these are the dukes that came of Eliphaz in the land of Edom; these were the sons of Adah.'); -INSERT INTO t1(docid,words) VALUES(1036017,'And these are the sons of Reuel Esau''s son; duke Nahath, duke Zerah, duke Shammah, duke Mizzah: these are the dukes that came of Reuel in the land of Edom; these are the sons of Bashemath Esau''s wife.'); -INSERT INTO t1(docid,words) VALUES(1036018,'And these are the sons of Aholibamah Esau''s wife; duke Jeush, duke Jaalam, duke Korah: these were the dukes that came of Aholibamah the daughter of Anah, Esau''s wife.'); -INSERT INTO t1(docid,words) VALUES(1036019,'These are the sons of Esau, who is Edom, and these are their dukes.'); -INSERT INTO t1(docid,words) VALUES(1036020,'These are the sons of Seir the Horite, who inhabited the land; Lotan, and Shobal, and Zibeon, and Anah,'); -INSERT INTO t1(docid,words) VALUES(1036021,'And Dishon, and Ezer, and Dishan: these are the dukes of the Horites, the children of Seir in the land of Edom.'); -INSERT INTO t1(docid,words) VALUES(1036022,'And the children of Lotan were Hori and Hemam; and Lotan''s sister was Timna.'); -INSERT INTO t1(docid,words) VALUES(1036023,'And the children of Shobal were these; Alvan, and Manahath, and Ebal, Shepho, and Onam.'); -INSERT INTO t1(docid,words) VALUES(1036024,'And these are the children of Zibeon; both Ajah, and Anah: this was that Anah that found the mules in the wilderness, as he fed the asses of Zibeon his father.'); -INSERT INTO t1(docid,words) VALUES(1036025,'And the children of Anah were these; Dishon, and Aholibamah the daughter of Anah.'); -INSERT INTO t1(docid,words) VALUES(1036026,'And these are the children of Dishon; Hemdan, and Eshban, and Ithran, and Cheran.'); -INSERT INTO t1(docid,words) VALUES(1036027,'The children of Ezer are these; Bilhan, and Zaavan, and Akan.'); -INSERT INTO t1(docid,words) VALUES(1036028,'The children of Dishan are these; Uz, and Aran.'); -INSERT INTO t1(docid,words) VALUES(1036029,'These are the dukes that came of the Horites; duke Lotan, duke Shobal, duke Zibeon, duke Anah,'); -INSERT INTO t1(docid,words) VALUES(1036030,'Duke Dishon, duke Ezer, duke Dishan: these are the dukes that came of Hori, among their dukes in the land of Seir.'); -INSERT INTO t1(docid,words) VALUES(1036031,'And these are the kings that reigned in the land of Edom, before there reigned any king over the children of Israel.'); -INSERT INTO t1(docid,words) VALUES(1036032,'And Bela the son of Beor reigned in Edom: and the name of his city was Dinhabah.'); -INSERT INTO t1(docid,words) VALUES(1036033,'And Bela died, and Jobab the son of Zerah of Bozrah reigned in his stead.'); -INSERT INTO t1(docid,words) VALUES(1036034,'And Jobab died, and Husham of the land of Temani reigned in his stead.'); -INSERT INTO t1(docid,words) VALUES(1036035,'And Husham died, and Hadad the son of Bedad, who smote Midian in the field of Moab, reigned in his stead: and the name of his city was Avith.'); -INSERT INTO t1(docid,words) VALUES(1036036,'And Hadad died, and Samlah of Masrekah reigned in his stead.'); -INSERT INTO t1(docid,words) VALUES(1036037,'And Samlah died, and Saul of Rehoboth by the river reigned in his stead.'); -INSERT INTO t1(docid,words) VALUES(1036038,'And Saul died, and Baalhanan the son of Achbor reigned in his stead.'); -INSERT INTO t1(docid,words) VALUES(1036039,'And Baalhanan the son of Achbor died, and Hadar reigned in his stead: and the name of his city was Pau; and his wife''s name was Mehetabel, the daughter of Matred, the daughter of Mezahab.'); -INSERT INTO t1(docid,words) VALUES(1036040,'And these are the names of the dukes that came of Esau, according to their families, after their places, by their names; duke Timnah, duke Alvah, duke Jetheth,'); -INSERT INTO t1(docid,words) VALUES(1036041,'Duke Aholibamah, duke Elah, duke Pinon,'); -INSERT INTO t1(docid,words) VALUES(1036042,'Duke Kenaz, duke Teman, duke Mibzar,'); -INSERT INTO t1(docid,words) VALUES(1036043,'Duke Magdiel, duke Iram: these be the dukes of Edom, according to their habitations in the land of their possession: he is Esau the father of the Edomites.'); -INSERT INTO t1(docid,words) VALUES(1037001,'And Jacob dwelt in the land wherein his father was a stranger, in the land of Canaan.'); -INSERT INTO t1(docid,words) VALUES(1037002,'These are the generations of Jacob. Joseph, being seventeen years old, was feeding the flock with his brethren; and the lad was with the sons of Bilhah, and with the sons of Zilpah, his father''s wives: and Joseph brought unto his father their evil report.'); -INSERT INTO t1(docid,words) VALUES(1037003,'Now Israel loved Joseph more than all his children, because he was the son of his old age: and he made him a coat of many colours.'); -INSERT INTO t1(docid,words) VALUES(1037004,'And when his brethren saw that their father loved him more than all his brethren, they hated him, and could not speak peaceably unto him.'); -INSERT INTO t1(docid,words) VALUES(1037005,'And Joseph dreamed a dream, and he told it his brethren: and they hated him yet the more.'); -INSERT INTO t1(docid,words) VALUES(1037006,'And he said unto them, Hear, I pray you, this dream which I have dreamed:'); -INSERT INTO t1(docid,words) VALUES(1037007,'For, behold, we were binding sheaves in the field, and, lo, my sheaf arose, and also stood upright; and, behold, your sheaves stood round about, and made obeisance to my sheaf.'); -INSERT INTO t1(docid,words) VALUES(1037008,'And his brethren said to him, Shalt thou indeed reign over us? or shalt thou indeed have dominion over us? And they hated him yet the more for his dreams, and for his words.'); -INSERT INTO t1(docid,words) VALUES(1037009,'And he dreamed yet another dream, and told it his brethren, and said, Behold, I have dreamed a dream more; and, behold, the sun and the moon and the eleven stars made obeisance to me.'); -INSERT INTO t1(docid,words) VALUES(1037010,'And he told it to his father, and to his brethren: and his father rebuked him, and said unto him, What is this dream that thou hast dreamed? Shall I and thy mother and thy brethren indeed come to bow down ourselves to thee to the earth?'); -INSERT INTO t1(docid,words) VALUES(1037011,'And his brethren envied him; but his father observed the saying.'); -INSERT INTO t1(docid,words) VALUES(1037012,'And his brethren went to feed their father''s flock in Shechem.'); -INSERT INTO t1(docid,words) VALUES(1037013,'And Israel said unto Joseph, Do not thy brethren feed the flock in Shechem? come, and I will send thee unto them. And he said to him, Here am I.'); -INSERT INTO t1(docid,words) VALUES(1037014,'And he said to him, Go, I pray thee, see whether it be well with thy brethren, and well with the flocks; and bring me word again. So he sent him out of the vale of Hebron, and he came to Shechem.'); -INSERT INTO t1(docid,words) VALUES(1037015,'And a certain man found him, and, behold, he was wandering in the field: and the man asked him, saying, What seekest thou?'); -INSERT INTO t1(docid,words) VALUES(1037016,'And he said, I seek my brethren: tell me, I pray thee, where they feed their flocks.'); -INSERT INTO t1(docid,words) VALUES(1037017,'And the man said, They are departed hence; for I heard them say, Let us go to Dothan. And Joseph went after his brethren, and found them in Dothan.'); -INSERT INTO t1(docid,words) VALUES(1037018,'And when they saw him afar off, even before he came near unto them, they conspired against him to slay him.'); -INSERT INTO t1(docid,words) VALUES(1037019,'And they said one to another, Behold, this dreamer cometh.'); -INSERT INTO t1(docid,words) VALUES(1037020,'Come now therefore, and let us slay him, and cast him into some pit, and we will say, Some evil beast hath devoured him: and we shall see what will become of his dreams.'); -INSERT INTO t1(docid,words) VALUES(1037021,'And Reuben heard it, and he delivered him out of their hands; and said, Let us not kill him.'); -INSERT INTO t1(docid,words) VALUES(1037022,'And Reuben said unto them, Shed no blood, but cast him into this pit that is in the wilderness, and lay no hand upon him; that he might rid him out of their hands, to deliver him to his father again.'); -INSERT INTO t1(docid,words) VALUES(1037023,'And it came to pass, when Joseph was come unto his brethren, that they stript Joseph out of his coat, his coat of many colours that was on him;'); -INSERT INTO t1(docid,words) VALUES(1037024,'And they took him, and cast him into a pit: and the pit was empty, there was no water in it.'); -INSERT INTO t1(docid,words) VALUES(1037025,'And they sat down to eat bread: and they lifted up their eyes and looked, and, behold, a company of Ishmeelites came from Gilead with their camels bearing spicery and balm and myrrh, going to carry it down to Egypt.'); -INSERT INTO t1(docid,words) VALUES(1037026,'And Judah said unto his brethren, What profit is it if we slay our brother, and conceal his blood?'); -INSERT INTO t1(docid,words) VALUES(1037027,'Come, and let us sell him to the Ishmeelites, and let not our hand be upon him; for he is our brother and our flesh. And his brethren were content.'); -INSERT INTO t1(docid,words) VALUES(1037028,'Then there passed by Midianites merchantmen; and they drew and lifted up Joseph out of the pit, and sold Joseph to the Ishmeelites for twenty pieces of silver: and they brought Joseph into Egypt.'); -INSERT INTO t1(docid,words) VALUES(1037029,'And Reuben returned unto the pit; and, behold, Joseph was not in the pit; and he rent his clothes.'); -INSERT INTO t1(docid,words) VALUES(1037030,'And he returned unto his brethren, and said, The child is not; and I, whither shall I go?'); -INSERT INTO t1(docid,words) VALUES(1037031,'And they took Joseph''s coat, and killed a kid of the goats, and dipped the coat in the blood;'); -INSERT INTO t1(docid,words) VALUES(1037032,'And they sent the coat of many colours, and they brought it to their father; and said, This have we found: know now whether it be thy son''s coat or no.'); -INSERT INTO t1(docid,words) VALUES(1037033,'And he knew it, and said, It is my son''s coat; an evil beast hath devoured him; Joseph is without doubt rent in pieces.'); -INSERT INTO t1(docid,words) VALUES(1037034,'And Jacob rent his clothes, and put sackcloth upon his loins, and mourned for his son many days.'); -INSERT INTO t1(docid,words) VALUES(1037035,'And all his sons and all his daughters rose up to comfort him; but he refused to be comforted; and he said, For I will go down into the grave unto my son mourning. Thus his father wept for him.'); -INSERT INTO t1(docid,words) VALUES(1037036,'And the Midianites sold him into Egypt unto Potiphar, an officer of Pharaoh''s, and captain of the guard.'); -INSERT INTO t1(docid,words) VALUES(1038001,'And it came to pass at that time, that Judah went down from his brethren, and turned in to a certain Adullamite, whose name was Hirah.'); -INSERT INTO t1(docid,words) VALUES(1038002,'And Judah saw there a daughter of a certain Canaanite, whose name was Shuah; and he took her, and went in unto her.'); -INSERT INTO t1(docid,words) VALUES(1038003,'And she conceived, and bare a son; and he called his name Er.'); -INSERT INTO t1(docid,words) VALUES(1038004,'And she conceived again, and bare a son; and she called his name Onan.'); -INSERT INTO t1(docid,words) VALUES(1038005,'And she yet again conceived, and bare a son; and called his name Shelah: and he was at Chezib, when she bare him.'); -INSERT INTO t1(docid,words) VALUES(1038006,'And Judah took a wife for Er his firstborn, whose name was Tamar.'); -INSERT INTO t1(docid,words) VALUES(1038007,'And Er, Judah''s firstborn, was wicked in the sight of the LORD; and the LORD slew him.'); -INSERT INTO t1(docid,words) VALUES(1038008,'And Judah said unto Onan, Go in unto thy brother''s wife, and marry her, and raise up seed to thy brother.'); -INSERT INTO t1(docid,words) VALUES(1038009,'And Onan knew that the seed should not be his; and it came to pass, when he went in unto his brother''s wife, that he spilled it on the ground, lest that he should give seed to his brother.'); -INSERT INTO t1(docid,words) VALUES(1038010,'And the thing which he did displeased the LORD: wherefore he slew him also.'); -INSERT INTO t1(docid,words) VALUES(1038011,'Then said Judah to Tamar his daughter in law, Remain a widow at thy father''s house, till Shelah my son be grown: for he said, Lest peradventure he die also, as his brethren did. And Tamar went and dwelt in her father''s house.'); -INSERT INTO t1(docid,words) VALUES(1038012,'And in process of time the daughter of Shuah Judah''s wife died; and Judah was comforted, and went up unto his sheepshearers to Timnath, he and his friend Hirah the Adullamite.'); -INSERT INTO t1(docid,words) VALUES(1038013,'And it was told Tamar, saying, Behold thy father in law goeth up to Timnath to shear his sheep.'); -INSERT INTO t1(docid,words) VALUES(1038014,'And she put her widow''s garments off from her, and covered her with a vail, and wrapped herself, and sat in an open place, which is by the way to Timnath; for she saw that Shelah was grown, and she was not given unto him to wife.'); -INSERT INTO t1(docid,words) VALUES(1038015,'When Judah saw her, he thought her to be an harlot; because she had covered her face.'); -INSERT INTO t1(docid,words) VALUES(1038016,'And he turned unto her by the way, and said, Go to, I pray thee, let me come in unto thee; (for he knew not that she was his daughter in law.) And she said, What wilt thou give me, that thou mayest come in unto me?'); -INSERT INTO t1(docid,words) VALUES(1038017,'And he said, I will send thee a kid from the flock. And she said, Wilt thou give me a pledge, till thou send it?'); -INSERT INTO t1(docid,words) VALUES(1038018,'And he said, What pledge shall I give thee? And she said, Thy signet, and thy bracelets, and thy staff that is in thine hand. And he gave it her, and came in unto her, and she conceived by him.'); -INSERT INTO t1(docid,words) VALUES(1038019,'And she arose, and went away, and laid by her vail from her, and put on the garments of her widowhood.'); -INSERT INTO t1(docid,words) VALUES(1038020,'And Judah sent the kid by the hand of his friend the Adullamite, to receive his pledge from the woman''s hand: but he found her not.'); -INSERT INTO t1(docid,words) VALUES(1038021,'Then he asked the men of that place, saying, Where is the harlot, that was openly by the way side? And they said, There was no harlot in this place.'); -INSERT INTO t1(docid,words) VALUES(1038022,'And he returned to Judah, and said, I cannot find her; and also the men of the place said, that there was no harlot in this place.'); -INSERT INTO t1(docid,words) VALUES(1038023,'And Judah said, Let her take it to her, lest we be shamed: behold, I sent this kid, and thou hast not found her.'); -INSERT INTO t1(docid,words) VALUES(1038024,'And it came to pass about three months after, that it was told Judah, saying, Tamar thy daughter in law hath played the harlot; and also, behold, she is with child by whoredom. And Judah said, Bring her forth, and let her be burnt.'); -INSERT INTO t1(docid,words) VALUES(1038025,'When she was brought forth, she sent to her father in law, saying, By the man, whose these are, am I with child: and she said, Discern, I pray thee, whose are these, the signet, and bracelets, and staff.'); -INSERT INTO t1(docid,words) VALUES(1038026,'And Judah acknowledged them, and said, She hath been more righteous than I; because that I gave her not to Shelah my son. And he knew her again no more.'); -INSERT INTO t1(docid,words) VALUES(1038027,'And it came to pass in the time of her travail, that, behold, twins were in her womb.'); -INSERT INTO t1(docid,words) VALUES(1038028,'And it came to pass, when she travailed, that the one put out his hand: and the midwife took and bound upon his hand a scarlet thread, saying, This came out first.'); -INSERT INTO t1(docid,words) VALUES(1038029,'And it came to pass, as he drew back his hand, that, behold, his brother came out: and she said, How hast thou broken forth? this breach be upon thee: therefore his name was called Pharez.'); -INSERT INTO t1(docid,words) VALUES(1038030,'And afterward came out his brother, that had the scarlet thread upon his hand: and his name was called Zarah.'); -INSERT INTO t1(docid,words) VALUES(1039001,'And Joseph was brought down to Egypt; and Potiphar, an officer of Pharaoh, captain of the guard, an Egyptian, bought him of the hands of the Ishmeelites, which had brought him down thither.'); -INSERT INTO t1(docid,words) VALUES(1039002,'And the LORD was with Joseph, and he was a prosperous man; and he was in the house of his master the Egyptian.'); -INSERT INTO t1(docid,words) VALUES(1039003,'And his master saw that the LORD was with him, and that the LORD made all that he did to prosper in his hand.'); -INSERT INTO t1(docid,words) VALUES(1039004,'And Joseph found grace in his sight, and he served him: and he made him overseer over his house, and all that he had he put into his hand.'); -INSERT INTO t1(docid,words) VALUES(1039005,'And it came to pass from the time that he had made him overseer in his house, and over all that he had, that the LORD blessed the Egyptian''s house for Joseph''s sake; and the blessing of the LORD was upon all that he had in the house, and in the field.'); -INSERT INTO t1(docid,words) VALUES(1039006,'And he left all that he had in Joseph''s hand; and he knew not ought he had, save the bread which he did eat. And Joseph was a goodly person, and well favoured.'); -INSERT INTO t1(docid,words) VALUES(1039007,'And it came to pass after these things, that his master''s wife cast her eyes upon Joseph; and she said, Lie with me.'); -INSERT INTO t1(docid,words) VALUES(1039008,'But he refused, and said unto his master''s wife, Behold, my master wotteth not what is with me in the house, and he hath committed all that he hath to my hand;'); -INSERT INTO t1(docid,words) VALUES(1039009,'There is none greater in this house than I; neither hath he kept back any thing from me but thee, because thou art his wife: how then can I do this great wickedness, and sin against God?'); -INSERT INTO t1(docid,words) VALUES(1039010,'And it came to pass, as she spake to Joseph day by day, that he hearkened not unto her, to lie by her, or to be with her.'); -INSERT INTO t1(docid,words) VALUES(1039011,'And it came to pass about this time, that Joseph went into the house to do his business; and there was none of the men of the house there within.'); -INSERT INTO t1(docid,words) VALUES(1039012,'And she caught him by his garment, saying, Lie with me: and he left his garment in her hand, and fled, and got him out.'); -INSERT INTO t1(docid,words) VALUES(1039013,'And it came to pass, when she saw that he had left his garment in her hand, and was fled forth,'); -INSERT INTO t1(docid,words) VALUES(1039014,'That she called unto the men of her house, and spake unto them, saying, See, he hath brought in an Hebrew unto us to mock us; he came in unto me to lie with me, and I cried with a loud voice:'); -INSERT INTO t1(docid,words) VALUES(1039015,'And it came to pass, when he heard that I lifted up my voice and cried, that he left his garment with me, and fled, and got him out.'); -INSERT INTO t1(docid,words) VALUES(1039016,'And she laid up his garment by her, until his lord came home.'); -INSERT INTO t1(docid,words) VALUES(1039017,'And she spake unto him according to these words, saying, The Hebrew servant, which thou hast brought unto us, came in unto me to mock me:'); -INSERT INTO t1(docid,words) VALUES(1039018,'And it came to pass, as I lifted up my voice and cried, that he left his garment with me, and fled out.'); -INSERT INTO t1(docid,words) VALUES(1039019,'And it came to pass, when his master heard the words of his wife, which she spake unto him, saying, After this manner did thy servant to me; that his wrath was kindled.'); -INSERT INTO t1(docid,words) VALUES(1039020,'And Joseph''s master took him, and put him into the prison, a place where the king''s prisoners were bound: and he was there in the prison.'); -INSERT INTO t1(docid,words) VALUES(1039021,'But the LORD was with Joseph, and shewed him mercy, and gave him favour in the sight of the keeper of the prison.'); -INSERT INTO t1(docid,words) VALUES(1039022,'And the keeper of the prison committed to Joseph''s hand all the prisoners that were in the prison; and whatsoever they did there, he was the doer of it.'); -INSERT INTO t1(docid,words) VALUES(1039023,'The keeper of the prison looked not to any thing that was under his hand; because the LORD was with him, and that which he did, the LORD made it to prosper.'); -INSERT INTO t1(docid,words) VALUES(1040001,'And it came to pass after these things, that the butler of the king of Egypt and his baker had offended their lord the king of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1040002,'And Pharaoh was wroth against two of his officers, against the chief of the butlers, and against the chief of the bakers.'); -INSERT INTO t1(docid,words) VALUES(1040003,'And he put them in ward in the house of the captain of the guard, into the prison, the place where Joseph was bound.'); -INSERT INTO t1(docid,words) VALUES(1040004,'And the captain of the guard charged Joseph with them, and he served them: and they continued a season in ward.'); -INSERT INTO t1(docid,words) VALUES(1040005,'And they dreamed a dream both of them, each man his dream in one night, each man according to the interpretation of his dream, the butler and the baker of the king of Egypt, which were bound in the prison.'); -INSERT INTO t1(docid,words) VALUES(1040006,'And Joseph came in unto them in the morning, and looked upon them, and, behold, they were sad.'); -INSERT INTO t1(docid,words) VALUES(1040007,'And he asked Pharaoh''s officers that were with him in the ward of his lord''s house, saying, Wherefore look ye so sadly to day?'); -INSERT INTO t1(docid,words) VALUES(1040008,'And they said unto him, We have dreamed a dream, and there is no interpreter of it. And Joseph said unto them, Do not interpretations belong to God? tell me them, I pray you.'); -INSERT INTO t1(docid,words) VALUES(1040009,'And the chief butler told his dream to Joseph, and said to him, In my dream, behold, a vine was before me;'); -INSERT INTO t1(docid,words) VALUES(1040010,'And in the vine were three branches: and it was as though it budded, and her blossoms shot forth; and the clusters thereof brought forth ripe grapes:'); -INSERT INTO t1(docid,words) VALUES(1040011,'And Pharaoh''s cup was in my hand: and I took the grapes, and pressed them into Pharaoh''s cup, and I gave the cup into Pharaoh''s hand.'); -INSERT INTO t1(docid,words) VALUES(1040012,'And Joseph said unto him, This is the interpretation of it: The three branches are three days:'); -INSERT INTO t1(docid,words) VALUES(1040013,'Yet within three days shall Pharaoh lift up thine head, and restore thee unto thy place: and thou shalt deliver Pharaoh''s cup into his hand, after the former manner when thou wast his butler.'); -INSERT INTO t1(docid,words) VALUES(1040014,'But think on me when it shall be well with thee, and shew kindness, I pray thee, unto me, and make mention of me unto Pharaoh, and bring me out of this house:'); -INSERT INTO t1(docid,words) VALUES(1040015,'For indeed I was stolen away out of the land of the Hebrews: and here also have I done nothing that they should put me into the dungeon.'); -INSERT INTO t1(docid,words) VALUES(1040016,'When the chief baker saw that the interpretation was good, he said unto Joseph, I also was in my dream, and, behold, I had three white baskets on my head:'); -INSERT INTO t1(docid,words) VALUES(1040017,'And in the uppermost basket there was of all manner of bakemeats for Pharaoh; and the birds did eat them out of the basket upon my head.'); -INSERT INTO t1(docid,words) VALUES(1040018,'And Joseph answered and said, This is the interpretation thereof: The three baskets are three days:'); -INSERT INTO t1(docid,words) VALUES(1040019,'Yet within three days shall Pharaoh lift up thy head from off thee, and shall hang thee on a tree; and the birds shall eat thy flesh from off thee.'); -INSERT INTO t1(docid,words) VALUES(1040020,'And it came to pass the third day, which was Pharaoh''s birthday, that he made a feast unto all his servants: and he lifted up the head of the chief butler and of the chief baker among his servants.'); -INSERT INTO t1(docid,words) VALUES(1040021,'And he restored the chief butler unto his butlership again; and he gave the cup into Pharaoh''s hand:'); -INSERT INTO t1(docid,words) VALUES(1040022,'But he hanged the chief baker: as Joseph had interpreted to them.'); -INSERT INTO t1(docid,words) VALUES(1040023,'Yet did not the chief butler remember Joseph, but forgat him.'); -INSERT INTO t1(docid,words) VALUES(1041001,'And it came to pass at the end of two full years, that Pharaoh dreamed: and, behold, he stood by the river.'); -INSERT INTO t1(docid,words) VALUES(1041002,'And, behold, there came up out of the river seven well favoured kine and fatfleshed; and they fed in a meadow.'); -INSERT INTO t1(docid,words) VALUES(1041003,'And, behold, seven other kine came up after them out of the river, ill favoured and leanfleshed; and stood by the other kine upon the brink of the river.'); -INSERT INTO t1(docid,words) VALUES(1041004,'And the ill favoured and leanfleshed kine did eat up the seven well favoured and fat kine. So Pharaoh awoke.'); -INSERT INTO t1(docid,words) VALUES(1041005,'And he slept and dreamed the second time: and, behold, seven ears of corn came up upon one stalk, rank and good.'); -INSERT INTO t1(docid,words) VALUES(1041006,'And, behold, seven thin ears and blasted with the east wind sprung up after them.'); -INSERT INTO t1(docid,words) VALUES(1041007,'And the seven thin ears devoured the seven rank and full ears. And Pharaoh awoke, and, behold, it was a dream.'); -INSERT INTO t1(docid,words) VALUES(1041008,'And it came to pass in the morning that his spirit was troubled; and he sent and called for all the magicians of Egypt, and all the wise men thereof: and Pharaoh told them his dream; but there was none that could interpret them unto Pharaoh.'); -INSERT INTO t1(docid,words) VALUES(1041009,'Then spake the chief butler unto Pharaoh, saying, I do remember my faults this day:'); -INSERT INTO t1(docid,words) VALUES(1041010,'Pharaoh was wroth with his servants, and put me in ward in the captain of the guard''s house, both me and the chief baker:'); -INSERT INTO t1(docid,words) VALUES(1041011,'And we dreamed a dream in one night, I and he; we dreamed each man according to the interpretation of his dream.'); -INSERT INTO t1(docid,words) VALUES(1041012,'And there was there with us a young man, an Hebrew, servant to the captain of the guard; and we told him, and he interpreted to us our dreams; to each man according to his dream he did interpret.'); -INSERT INTO t1(docid,words) VALUES(1041013,'And it came to pass, as he interpreted to us, so it was; me he restored unto mine office, and him he hanged.'); -INSERT INTO t1(docid,words) VALUES(1041014,'Then Pharaoh sent and called Joseph, and they brought him hastily out of the dungeon: and he shaved himself, and changed his raiment, and came in unto Pharaoh.'); -INSERT INTO t1(docid,words) VALUES(1041015,'And Pharaoh said unto Joseph, I have dreamed a dream, and there is none that can interpret it: and I have heard say of thee, that thou canst understand a dream to interpret it.'); -INSERT INTO t1(docid,words) VALUES(1041016,'And Joseph answered Pharaoh, saying, It is not in me: God shall give Pharaoh an answer of peace.'); -INSERT INTO t1(docid,words) VALUES(1041017,'And Pharaoh said unto Joseph, In my dream, behold, I stood upon the bank of the river:'); -INSERT INTO t1(docid,words) VALUES(1041018,'And, behold, there came up out of the river seven kine, fatfleshed and well favoured; and they fed in a meadow:'); -INSERT INTO t1(docid,words) VALUES(1041019,'And, behold, seven other kine came up after them, poor and very ill favoured and leanfleshed, such as I never saw in all the land of Egypt for badness:'); -INSERT INTO t1(docid,words) VALUES(1041020,'And the lean and the ill favoured kine did eat up the first seven fat kine:'); -INSERT INTO t1(docid,words) VALUES(1041021,'And when they had eaten them up, it could not be known that they had eaten them; but they were still ill favoured, as at the beginning. So I awoke.'); -INSERT INTO t1(docid,words) VALUES(1041022,'And I saw in my dream, and, behold, seven ears came up in one stalk, full and good:'); -INSERT INTO t1(docid,words) VALUES(1041023,'And, behold, seven ears, withered, thin, and blasted with the east wind, sprung up after them:'); -INSERT INTO t1(docid,words) VALUES(1041024,'And the thin ears devoured the seven good ears: and I told this unto the magicians; but there was none that could declare it to me.'); -INSERT INTO t1(docid,words) VALUES(1041025,'And Joseph said unto Pharaoh, The dream of Pharaoh is one: God hath shewed Pharaoh what he is about to do.'); -INSERT INTO t1(docid,words) VALUES(1041026,'The seven good kine are seven years; and the seven good ears are seven years: the dream is one.'); -INSERT INTO t1(docid,words) VALUES(1041027,'And the seven thin and ill favoured kine that came up after them are seven years; and the seven empty ears blasted with the east wind shall be seven years of famine.'); -INSERT INTO t1(docid,words) VALUES(1041028,'This is the thing which I have spoken unto Pharaoh: What God is about to do he sheweth unto Pharaoh.'); -INSERT INTO t1(docid,words) VALUES(1041029,'Behold, there come seven years of great plenty throughout all the land of Egypt:'); -INSERT INTO t1(docid,words) VALUES(1041030,'And there shall arise after them seven years of famine; and all the plenty shall be forgotten in the land of Egypt; and the famine shall consume the land;'); -INSERT INTO t1(docid,words) VALUES(1041031,'And the plenty shall not be known in the land by reason of that famine following; for it shall be very grievous.'); -INSERT INTO t1(docid,words) VALUES(1041032,'And for that the dream was doubled unto Pharaoh twice; it is because the thing is established by God, and God will shortly bring it to pass.'); -INSERT INTO t1(docid,words) VALUES(1041033,'Now therefore let Pharaoh look out a man discreet and wise, and set him over the land of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1041034,'Let Pharaoh do this, and let him appoint officers over the land, and take up the fifth part of the land of Egypt in the seven plenteous years.'); -INSERT INTO t1(docid,words) VALUES(1041035,'And let them gather all the food of those good years that come, and lay up corn under the hand of Pharaoh, and let them keep food in the cities.'); -INSERT INTO t1(docid,words) VALUES(1041036,'And that food shall be for store to the land against the seven years of famine, which shall be in the land of Egypt; that the land perish not through the famine.'); -INSERT INTO t1(docid,words) VALUES(1041037,'And the thing was good in the eyes of Pharaoh, and in the eyes of all his servants.'); -INSERT INTO t1(docid,words) VALUES(1041038,'And Pharaoh said unto his servants, Can we find such a one as this is, a man in whom the Spirit of God is?'); -INSERT INTO t1(docid,words) VALUES(1041039,'And Pharaoh said unto Joseph, Forasmuch as God hath shewed thee all this, there is none so discreet and wise as thou art:'); -INSERT INTO t1(docid,words) VALUES(1041040,'Thou shalt be over my house, and according unto thy word shall all my people be ruled: only in the throne will I be greater than thou.'); -INSERT INTO t1(docid,words) VALUES(1041041,'And Pharaoh said unto Joseph, See, I have set thee over all the land of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1041042,'And Pharaoh took off his ring from his hand, and put it upon Joseph''s hand, and arrayed him in vestures of fine linen, and put a gold chain about his neck;'); -INSERT INTO t1(docid,words) VALUES(1041043,'And he made him to ride in the second chariot which he had; and they cried before him, Bow the knee: and he made him ruler over all the land of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1041044,'And Pharaoh said unto Joseph, I am Pharaoh, and without thee shall no man lift up his hand or foot in all the land of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1041045,'And Pharaoh called Joseph''s name Zaphnathpaaneah; and he gave him to wife Asenath the daughter of Potipherah priest of On. And Joseph went out over all the land of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1041046,'And Joseph was thirty years old when he stood before Pharaoh king of Egypt. And Joseph went out from the presence of Pharaoh, and went throughout all the land of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1041047,'And in the seven plenteous years the earth brought forth by handfuls.'); -INSERT INTO t1(docid,words) VALUES(1041048,'And he gathered up all the food of the seven years, which were in the land of Egypt, and laid up the food in the cities: the food of the field, which was round about every city, laid he up in the same.'); -INSERT INTO t1(docid,words) VALUES(1041049,'And Joseph gathered corn as the sand of the sea, very much, until he left numbering; for it was without number.'); -INSERT INTO t1(docid,words) VALUES(1041050,'And unto Joseph were born two sons before the years of famine came, which Asenath the daughter of Potipherah priest of On bare unto him.'); -INSERT INTO t1(docid,words) VALUES(1041051,'And Joseph called the name of the firstborn Manasseh: For God, said he, hath made me forget all my toil, and all my father''s house.'); -INSERT INTO t1(docid,words) VALUES(1041052,'And the name of the second called he Ephraim: For God hath caused me to be fruitful in the land of my affliction.'); -INSERT INTO t1(docid,words) VALUES(1041053,'And the seven years of plenteousness, that was in the land of Egypt, were ended.'); -INSERT INTO t1(docid,words) VALUES(1041054,'And the seven years of dearth began to come, according as Joseph had said: and the dearth was in all lands; but in all the land of Egypt there was bread.'); -INSERT INTO t1(docid,words) VALUES(1041055,'And when all the land of Egypt was famished, the people cried to Pharaoh for bread: and Pharaoh said unto all the Egyptians, Go unto Joseph; what he saith to you, do.'); -INSERT INTO t1(docid,words) VALUES(1041056,'And the famine was over all the face of the earth: and Joseph opened all the storehouses, and sold unto the Egyptians; and the famine waxed sore in the land of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1041057,'And all countries came into Egypt to Joseph for to buy corn; because that the famine was so sore in all lands.'); -INSERT INTO t1(docid,words) VALUES(1042001,'Now when Jacob saw that there was corn in Egypt, Jacob said unto his sons, Why do ye look one upon another?'); -INSERT INTO t1(docid,words) VALUES(1042002,'And he said, Behold, I have heard that there is corn in Egypt: get you down thither, and buy for us from thence; that we may live, and not die.'); -INSERT INTO t1(docid,words) VALUES(1042003,'And Joseph''s ten brethren went down to buy corn in Egypt.'); -INSERT INTO t1(docid,words) VALUES(1042004,'But Benjamin, Joseph''s brother, Jacob sent not with his brethren; for he said, Lest peradventure mischief befall him.'); -INSERT INTO t1(docid,words) VALUES(1042005,'And the sons of Israel came to buy corn among those that came: for the famine was in the land of Canaan.'); -INSERT INTO t1(docid,words) VALUES(1042006,'And Joseph was the governor over the land, and he it was that sold to all the people of the land: and Joseph''s brethren came, and bowed down themselves before him with their faces to the earth.'); -INSERT INTO t1(docid,words) VALUES(1042007,'And Joseph saw his brethren, and he knew them, but made himself strange unto them, and spake roughly unto them; and he said unto them, Whence come ye? And they said, From the land of Canaan to buy food.'); -INSERT INTO t1(docid,words) VALUES(1042008,'And Joseph knew his brethren, but they knew not him.'); -INSERT INTO t1(docid,words) VALUES(1042009,'And Joseph remembered the dreams which he dreamed of them, and said unto them, Ye are spies; to see the nakedness of the land ye are come.'); -INSERT INTO t1(docid,words) VALUES(1042010,'And they said unto him, Nay, my lord, but to buy food are thy servants come.'); -INSERT INTO t1(docid,words) VALUES(1042011,'We are all one man''s sons; we are true men, thy servants are no spies.'); -INSERT INTO t1(docid,words) VALUES(1042012,'And he said unto them, Nay, but to see the nakedness of the land ye are come.'); -INSERT INTO t1(docid,words) VALUES(1042013,'And they said, Thy servants are twelve brethren, the sons of one man in the land of Canaan; and, behold, the youngest is this day with our father, and one is not.'); -INSERT INTO t1(docid,words) VALUES(1042014,'And Joseph said unto them, That is it that I spake unto you, saying, Ye are spies:'); -INSERT INTO t1(docid,words) VALUES(1042015,'Hereby ye shall be proved: By the life of Pharaoh ye shall not go forth hence, except your youngest brother come hither.'); -INSERT INTO t1(docid,words) VALUES(1042016,'Send one of you, and let him fetch your brother, and ye shall be kept in prison, that your words may be proved, whether there be any truth in you: or else by the life of Pharaoh surely ye are spies.'); -INSERT INTO t1(docid,words) VALUES(1042017,'And he put them all together into ward three days.'); -INSERT INTO t1(docid,words) VALUES(1042018,'And Joseph said unto them the third day, This do, and live; for I fear God:'); -INSERT INTO t1(docid,words) VALUES(1042019,'If ye be true men, let one of your brethren be bound in the house of your prison: go ye, carry corn for the famine of your houses:'); -INSERT INTO t1(docid,words) VALUES(1042020,'But bring your youngest brother unto me; so shall your words be verified, and ye shall not die. And they did so.'); -INSERT INTO t1(docid,words) VALUES(1042021,'And they said one to another, We are verily guilty concerning our brother, in that we saw the anguish of his soul, when he besought us, and we would not hear; therefore is this distress come upon us.'); -INSERT INTO t1(docid,words) VALUES(1042022,'And Reuben answered them, saying, Spake I not unto you, saying, Do not sin against the child; and ye would not hear? therefore, behold, also his blood is required.'); -INSERT INTO t1(docid,words) VALUES(1042023,'And they knew not that Joseph understood them; for he spake unto them by an interpreter.'); -INSERT INTO t1(docid,words) VALUES(1042024,'And he turned himself about from them, and wept; and returned to them again, and communed with them, and took from them Simeon, and bound him before their eyes.'); -INSERT INTO t1(docid,words) VALUES(1042025,'Then Joseph commanded to fill their sacks with corn, and to restore every man''s money into his sack, and to give them provision for the way: and thus did he unto them.'); -INSERT INTO t1(docid,words) VALUES(1042026,'And they laded their asses with the corn, and departed thence.'); -INSERT INTO t1(docid,words) VALUES(1042027,'And as one of them opened his sack to give his ass provender in the inn, he espied his money; for, behold, it was in his sack''s mouth.'); -INSERT INTO t1(docid,words) VALUES(1042028,'And he said unto his brethren, My money is restored; and, lo, it is even in my sack: and their heart failed them, and they were afraid, saying one to another, What is this that God hath done unto us?'); -INSERT INTO t1(docid,words) VALUES(1042029,'And they came unto Jacob their father unto the land of Canaan, and told him all that befell unto them; saying,'); -INSERT INTO t1(docid,words) VALUES(1042030,'The man, who is the lord of the land, spake roughly to us, and took us for spies of the country.'); -INSERT INTO t1(docid,words) VALUES(1042031,'And we said unto him, We are true men; we are no spies:'); -INSERT INTO t1(docid,words) VALUES(1042032,'We be twelve brethren, sons of our father; one is not, and the youngest is this day with our father in the land of Canaan.'); -INSERT INTO t1(docid,words) VALUES(1042033,'And the man, the lord of the country, said unto us, Hereby shall I know that ye are true men; leave one of your brethren here with me, and take food for the famine of your households, and be gone:'); -INSERT INTO t1(docid,words) VALUES(1042034,'And bring your youngest brother unto me: then shall I know that ye are no spies, but that ye are true men: so will I deliver you your brother, and ye shall traffick in the land.'); -INSERT INTO t1(docid,words) VALUES(1042035,'And it came to pass as they emptied their sacks, that, behold, every man''s bundle of money was in his sack: and when both they and their father saw the bundles of money, they were afraid.'); -INSERT INTO t1(docid,words) VALUES(1042036,'And Jacob their father said unto them, Me have ye bereaved of my children: Joseph is not, and Simeon is not, and ye will take Benjamin away: all these things are against me.'); -INSERT INTO t1(docid,words) VALUES(1042037,'And Reuben spake unto his father, saying, Slay my two sons, if I bring him not to thee: deliver him into my hand, and I will bring him to thee again.'); -INSERT INTO t1(docid,words) VALUES(1042038,'And he said, My son shall not go down with you; for his brother is dead, and he is left alone: if mischief befall him by the way in the which ye go, then shall ye bring down my gray hairs with sorrow to the grave.'); -INSERT INTO t1(docid,words) VALUES(1043001,'And the famine was sore in the land.'); -INSERT INTO t1(docid,words) VALUES(1043002,'And it came to pass, when they had eaten up the corn which they had brought out of Egypt, their father said unto them, Go again, buy us a little food.'); -INSERT INTO t1(docid,words) VALUES(1043003,'And Judah spake unto him, saying, The man did solemnly protest unto us, saying, Ye shall not see my face, except your brother be with you.'); -INSERT INTO t1(docid,words) VALUES(1043004,'If thou wilt send our brother with us, we will go down and buy thee food:'); -INSERT INTO t1(docid,words) VALUES(1043005,'But if thou wilt not send him, we will not go down: for the man said unto us, Ye shall not see my face, except your brother be with you.'); -INSERT INTO t1(docid,words) VALUES(1043006,'And Israel said, Wherefore dealt ye so ill with me, as to tell the man whether ye had yet a brother?'); -INSERT INTO t1(docid,words) VALUES(1043007,'And they said, The man asked us straitly of our state, and of our kindred, saying, Is your father yet alive? have ye another brother? and we told him according to the tenor of these words: could we certainly know that he would say, Bring your brother down?'); -INSERT INTO t1(docid,words) VALUES(1043008,'And Judah said unto Israel his father, Send the lad with me, and we will arise and go; that we may live, and not die, both we, and thou, and also our little ones.'); -INSERT INTO t1(docid,words) VALUES(1043009,'I will be surety for him; of my hand shalt thou require him: if I bring him not unto thee, and set him before thee, then let me bear the blame for ever:'); -INSERT INTO t1(docid,words) VALUES(1043010,'For except we had lingered, surely now we had returned this second time.'); -INSERT INTO t1(docid,words) VALUES(1043011,'And their father Israel said unto them, If it must be so now, do this; take of the best fruits in the land in your vessels, and carry down the man a present, a little balm, and a little honey, spices, and myrrh, nuts, and almonds:'); -INSERT INTO t1(docid,words) VALUES(1043012,'And take double money in your hand; and the money that was brought again in the mouth of your sacks, carry it again in your hand; peradventure it was an oversight:'); -INSERT INTO t1(docid,words) VALUES(1043013,'Take also your brother, and arise, go again unto the man:'); -INSERT INTO t1(docid,words) VALUES(1043014,'And God Almighty give you mercy before the man, that he may send away your other brother, and Benjamin. If I be bereaved of my children, I am bereaved.'); -INSERT INTO t1(docid,words) VALUES(1043015,'And the men took that present, and they took double money in their hand and Benjamin; and rose up, and went down to Egypt, and stood before Joseph.'); -INSERT INTO t1(docid,words) VALUES(1043016,'And when Joseph saw Benjamin with them, he said to the ruler of his house, Bring these men home, and slay, and make ready; for these men shall dine with me at noon.'); -INSERT INTO t1(docid,words) VALUES(1043017,'And the man did as Joseph bade; and the man brought the men into Joseph''s house.'); -INSERT INTO t1(docid,words) VALUES(1043018,'And the men were afraid, because they were brought into Joseph''s house; and they said, Because of the money that was returned in our sacks at the first time are we brought in; that he may seek occasion against us, and fall upon us, and take us for bondmen, and our asses.'); -INSERT INTO t1(docid,words) VALUES(1043019,'And they came near to the steward of Joseph''s house, and they communed with him at the door of the house,'); -INSERT INTO t1(docid,words) VALUES(1043020,'And said, O sir, we came indeed down at the first time to buy food:'); -INSERT INTO t1(docid,words) VALUES(1043021,'And it came to pass, when we came to the inn, that we opened our sacks, and, behold, every man''s money was in the mouth of his sack, our money in full weight: and we have brought it again in our hand.'); -INSERT INTO t1(docid,words) VALUES(1043022,'And other money have we brought down in our hands to buy food: we cannot tell who put our money in our sacks.'); -INSERT INTO t1(docid,words) VALUES(1043023,'And he said, Peace be to you, fear not: your God, and the God of your father, hath given you treasure in your sacks: I had your money. And he brought Simeon out unto them.'); -INSERT INTO t1(docid,words) VALUES(1043024,'And the man brought the men into Joseph''s house, and gave them water, and they washed their feet; and he gave their asses provender.'); -INSERT INTO t1(docid,words) VALUES(1043025,'And they made ready the present against Joseph came at noon: for they heard that they should eat bread there.'); -INSERT INTO t1(docid,words) VALUES(1043026,'And when Joseph came home, they brought him the present which was in their hand into the house, and bowed themselves to him to the earth.'); -INSERT INTO t1(docid,words) VALUES(1043027,'And he asked them of their welfare, and said, Is your father well, the old man of whom ye spake? Is he yet alive?'); -INSERT INTO t1(docid,words) VALUES(1043028,'And they answered, Thy servant our father is in good health, he is yet alive. And they bowed down their heads, and made obeisance.'); -INSERT INTO t1(docid,words) VALUES(1043029,'And he lifted up his eyes, and saw his brother Benjamin, his mother''s son, and said, Is this your younger brother, of whom ye spake unto me? And he said, God be gracious unto thee, my son.'); -INSERT INTO t1(docid,words) VALUES(1043030,'And Joseph made haste; for his bowels did yearn upon his brother: and he sought where to weep; and he entered into his chamber, and wept there.'); -INSERT INTO t1(docid,words) VALUES(1043031,'And he washed his face, and went out, and refrained himself, and said, Set on bread.'); -INSERT INTO t1(docid,words) VALUES(1043032,'And they set on for him by himself, and for them by themselves, and for the Egyptians, which did eat with him, by themselves: because the Egyptians might not eat bread with the Hebrews; for that is an abomination unto the Egyptians.'); -INSERT INTO t1(docid,words) VALUES(1043033,'And they sat before him, the firstborn according to his birthright, and the youngest according to his youth: and the men marvelled one at another.'); -INSERT INTO t1(docid,words) VALUES(1043034,'And he took and sent messes unto them from before him: but Benjamin''s mess was five times so much as any of their''s. And they drank, and were merry with him.'); -INSERT INTO t1(docid,words) VALUES(1044001,'And he commanded the steward of his house, saying, Fill the men''s sacks with food, as much as they can carry, and put every man''s money in his sack''s mouth.'); -INSERT INTO t1(docid,words) VALUES(1044002,'And put my cup, the silver cup, in the sack''s mouth of the youngest, and his corn money. And he did according to the word that Joseph had spoken.'); -INSERT INTO t1(docid,words) VALUES(1044003,'As soon as the morning was light, the men were sent away, they and their asses.'); -INSERT INTO t1(docid,words) VALUES(1044004,'And when they were gone out of the city, and not yet far off, Joseph said unto his steward, Up, follow after the men; and when thou dost overtake them, say unto them, Wherefore have ye rewarded evil for good?'); -INSERT INTO t1(docid,words) VALUES(1044005,'Is not this it in which my lord drinketh, and whereby indeed he divineth? ye have done evil in so doing.'); -INSERT INTO t1(docid,words) VALUES(1044006,'And he overtook them, and he spake unto them these same words.'); -INSERT INTO t1(docid,words) VALUES(1044007,'And they said unto him, Wherefore saith my lord these words? God forbid that thy servants should do according to this thing:'); -INSERT INTO t1(docid,words) VALUES(1044008,'Behold, the money, which we found in our sacks'' mouths, we brought again unto thee out of the land of Canaan: how then should we steal out of thy lord''s house silver or gold?'); -INSERT INTO t1(docid,words) VALUES(1044009,'With whomsoever of thy servants it be found, both let him die, and we also will be my lord''s bondmen.'); -INSERT INTO t1(docid,words) VALUES(1044010,'And he said, Now also let it be according unto your words: he with whom it is found shall be my servant; and ye shall be blameless.'); -INSERT INTO t1(docid,words) VALUES(1044011,'Then they speedily took down every man his sack to the ground, and opened every man his sack.'); -INSERT INTO t1(docid,words) VALUES(1044012,'And he searched, and began at the eldest, and left at the youngest: and the cup was found in Benjamin''s sack.'); -INSERT INTO t1(docid,words) VALUES(1044013,'Then they rent their clothes, and laded every man his ass, and returned to the city.'); -INSERT INTO t1(docid,words) VALUES(1044014,'And Judah and his brethren came to Joseph''s house; for he was yet there: and they fell before him on the ground.'); -INSERT INTO t1(docid,words) VALUES(1044015,'And Joseph said unto them, What deed is this that ye have done? wot ye not that such a man as I can certainly divine?'); -INSERT INTO t1(docid,words) VALUES(1044016,'And Judah said, What shall we say unto my lord? what shall we speak? or how shall we clear ourselves? God hath found out the iniquity of thy servants: behold, we are my lord''s servants, both we, and he also with whom the cup is found.'); -INSERT INTO t1(docid,words) VALUES(1044017,'And he said, God forbid that I should do so: but the man in whose hand the cup is found, he shall be my servant; and as for you, get you up in peace unto your father.'); -INSERT INTO t1(docid,words) VALUES(1044018,'Then Judah came near unto him, and said, Oh my lord, let thy servant, I pray thee, speak a word in my lord''s ears, and let not thine anger burn against thy servant: for thou art even as Pharaoh.'); -INSERT INTO t1(docid,words) VALUES(1044019,'My lord asked his servants, saying, Have ye a father, or a brother?'); -INSERT INTO t1(docid,words) VALUES(1044020,'And we said unto my lord, We have a father, an old man, and a child of his old age, a little one; and his brother is dead, and he alone is left of his mother, and his father loveth him.'); -INSERT INTO t1(docid,words) VALUES(1044021,'And thou saidst unto thy servants, Bring him down unto me, that I may set mine eyes upon him.'); -INSERT INTO t1(docid,words) VALUES(1044022,'And we said unto my lord, The lad cannot leave his father: for if he should leave his father, his father would die.'); -INSERT INTO t1(docid,words) VALUES(1044023,'And thou saidst unto thy servants, Except your youngest brother come down with you, ye shall see my face no more.'); -INSERT INTO t1(docid,words) VALUES(1044024,'And it came to pass when we came up unto thy servant my father, we told him the words of my lord.'); -INSERT INTO t1(docid,words) VALUES(1044025,'And our father said, Go again, and buy us a little food.'); -INSERT INTO t1(docid,words) VALUES(1044026,'And we said, We cannot go down: if our youngest brother be with us, then will we go down: for we may not see the man''s face, except our youngest brother be with us.'); -INSERT INTO t1(docid,words) VALUES(1044027,'And thy servant my father said unto us, Ye know that my wife bare me two sons:'); -INSERT INTO t1(docid,words) VALUES(1044028,'And the one went out from me, and I said, Surely he is torn in pieces; and I saw him not since:'); -INSERT INTO t1(docid,words) VALUES(1044029,'And if ye take this also from me, and mischief befall him, ye shall bring down my gray hairs with sorrow to the grave.'); -INSERT INTO t1(docid,words) VALUES(1044030,'Now therefore when I come to thy servant my father, and the lad be not with us; seeing that his life is bound up in the lad''s life;'); -INSERT INTO t1(docid,words) VALUES(1044031,'It shall come to pass, when he seeth that the lad is not with us, that he will die: and thy servants shall bring down the gray hairs of thy servant our father with sorrow to the grave.'); -INSERT INTO t1(docid,words) VALUES(1044032,'For thy servant became surety for the lad unto my father, saying, If I bring him not unto thee, then I shall bear the blame to my father for ever.'); -INSERT INTO t1(docid,words) VALUES(1044033,'Now therefore, I pray thee, let thy servant abide instead of the lad a bondman to my lord; and let the lad go up with his brethren.'); -INSERT INTO t1(docid,words) VALUES(1044034,'For how shall I go up to my father, and the lad be not with me? lest peradventure I see the evil that shall come on my father.'); -INSERT INTO t1(docid,words) VALUES(1045001,'Then Joseph could not refrain himself before all them that stood by him; and he cried, Cause every man to go out from me. And there stood no man with him, while Joseph made himself known unto his brethren.'); -INSERT INTO t1(docid,words) VALUES(1045002,'And he wept aloud: and the Egyptians and the house of Pharaoh heard.'); -INSERT INTO t1(docid,words) VALUES(1045003,'And Joseph said unto his brethren, I am Joseph; doth my father yet live? And his brethren could not answer him; for they were troubled at his presence.'); -INSERT INTO t1(docid,words) VALUES(1045004,'And Joseph said unto his brethren, Come near to me, I pray you. And they came near. And he said, I am Joseph your brother, whom ye sold into Egypt.'); -INSERT INTO t1(docid,words) VALUES(1045005,'Now therefore be not grieved, nor angry with yourselves, that ye sold me hither: for God did send me before you to preserve life.'); -INSERT INTO t1(docid,words) VALUES(1045006,'For these two years hath the famine been in the land: and yet there are five years, in the which there shall neither be earing nor harvest.'); -INSERT INTO t1(docid,words) VALUES(1045007,'And God sent me before you to preserve you a posterity in the earth, and to save your lives by a great deliverance.'); -INSERT INTO t1(docid,words) VALUES(1045008,'So now it was not you that sent me hither, but God: and he hath made me a father to Pharaoh, and lord of all his house, and a ruler throughout all the land of Egypt.'); -INSERT INTO t1(docid,words) VALUES(1045009,'Haste ye, and go up to my father, and say unto him, Thus saith thy son Joseph, God hath made me lord of all Egypt: come down unto me, tarry not:'); -INSERT INTO t1(docid,words) VALUES(1045010,'And thou shalt dwell in the land of Goshen, and thou shalt be near unto me, thou, and thy children, and thy children''s children, and thy flocks, and thy herds, and all that thou hast:'); -INSERT INTO t1(docid,words) VALUES(1045011,'And there will I nourish thee; for yet there are five years of famine; lest thou, and thy household, and all that thou hast, come to poverty.'); -INSERT INTO t1(docid,words) VALUES(1045012,'And, behold, your eyes see, and the eyes of my brother Benjamin, that it is my mouth that speaketh unto you.'); -INSERT INTO t1(docid,words) VALUES(1045013,'And ye shall tell my father of all my glory in Egypt, and of all that ye have seen; and ye shall haste and bring down my father hither.'); -INSERT INTO t1(docid,words) VALUES(1045014,'And he fell upon his brother Benjamin''s neck, and wept; and Benjamin wept upon his neck.'); -INSERT INTO t1(docid,words) VALUES(1045015,'Moreover he kissed all his brethren, and wept upon them: and after that his brethren talked with him.'); -INSERT INTO t1(docid,words) VALUES(1045016,'And the fame thereof was heard in Pharaoh''s house, saying, Joseph''s brethren are come: and it pleased Pharaoh well, and his servants.'); -INSERT INTO t1(docid,words) VALUES(1045017,'And Pharaoh said unto Joseph, Say unto thy brethren, This do ye; lade your beasts, and go, get you unto the land of Canaan;'); -INSERT INTO t1(docid,words) VALUES(1045018,'And take your father and your households, and come unto me: and I will give you the good of the land of Egypt, and ye shall eat the fat of the land.'); -INSERT INTO t1(docid,words) VALUES(1045019,'Now thou art commanded, this do ye; take you wagons out of the land of Egypt for your little ones, and for your wives, and bring your father, and come.'); -INSERT INTO t1(docid,words) VALUES(1045020,'Also regard not your stuff; for the good of all the land of Egypt is your''s.'); -INSERT INTO t1(docid,words) VALUES(1045021,'And the children of Israel did so: and Joseph gave them wagons, according to the commandment of Pharaoh, and gave them provision for the way.'); -INSERT INTO t1(docid,words) VALUES(1045022,'To all of them he gave each man changes of raiment; but to Benjamin he gave three hundred pieces of silver, and five changes of raiment.'); -INSERT INTO t1(docid,words) VALUES(1045023,'And to his father he sent after this manner; ten asses laden with the good things of Egypt, and ten she asses laden with corn and bread and meat for his father by the way.'); -INSERT INTO t1(docid,words) VALUES(1045024,'So he sent his brethren away, and they departed: and he said unto them, See that ye fall not out by the way.'); -INSERT INTO t1(docid,words) VALUES(1045025,'And they went up out of Egypt, and came into the land of Canaan unto Jacob their father,'); -INSERT INTO t1(docid,words) VALUES(1045026,'And told him, saying, Joseph is yet alive, and he is governor over all the land of Egypt. And Jacob''s heart fainted, for he believed them not.'); -INSERT INTO t1(docid,words) VALUES(1045027,'And they told him all the words of Joseph, which he had said unto them: and when he saw the wagons which Joseph had sent to carry him, the spirit of Jacob their father revived:'); -INSERT INTO t1(docid,words) VALUES(1045028,'And Israel said, It is enough; Joseph my son is yet alive: I will go and see him before I die.'); -INSERT INTO t1(docid,words) VALUES(1046001,'And Israel took his journey with all that he had, and came to Beersheba, and offered sacrifices unto the God of his father Isaac.'); -INSERT INTO t1(docid,words) VALUES(1046002,'And God spake unto Israel in the visions of the night, and said, Jacob, Jacob. And he said, Here am I.'); -INSERT INTO t1(docid,words) VALUES(1046003,'And he said, I am God, the God of thy father: fear not to go down into Egypt; for I will there make of thee a great nation:'); -INSERT INTO t1(docid,words) VALUES(1046004,'I will go down with thee into Egypt; and I will also surely bring thee up again: and Joseph shall put his hand upon thine eyes.'); -INSERT INTO t1(docid,words) VALUES(1046005,'And Jacob rose up from Beersheba: and the sons of Israel carried Jacob their father, and their little ones, and their wives, in the wagons which Pharaoh had sent to carry him.'); -INSERT INTO t1(docid,words) VALUES(1046006,'And they took their cattle, and their goods, which they had gotten in the land of Canaan, and came into Egypt, Jacob, and all his seed with him:'); -INSERT INTO t1(docid,words) VALUES(1046007,'His sons, and his sons'' sons with him, his daughters, and his sons'' daughters, and all his seed brought he with him into Egypt.'); -INSERT INTO t1(docid,words) VALUES(1046008,'And these are the names of the children of Israel, which came into Egypt, Jacob and his sons: Reuben, Jacob''s firstborn.'); -INSERT INTO t1(docid,words) VALUES(1046009,'And the sons of Reuben; Hanoch, and Phallu, and Hezron, and Carmi.'); -INSERT INTO t1(docid,words) VALUES(1046010,'And the sons of Simeon; Jemuel, and Jamin, and Ohad, and Jachin, and Zohar, and Shaul the son of a Canaanitish woman.'); -INSERT INTO t1(docid,words) VALUES(1046011,'And the sons of Levi; Gershon, Kohath, and Merari.'); -INSERT INTO t1(docid,words) VALUES(1046012,'And the sons of Judah; Er, and Onan, and Shelah, and Pharez, and Zarah: but Er and Onan died in the land of Canaan. And the sons of Pharez were Hezron and Hamul.'); -INSERT INTO t1(docid,words) VALUES(1046013,'And the sons of Issachar; Tola, and Phuvah, and Job, and Shimron.'); -INSERT INTO t1(docid,words) VALUES(1046014,'And the sons of Zebulun; Sered, and Elon, and Jahleel.'); -INSERT INTO t1(docid,words) VALUES(1046015,'These be the sons of Leah, which she bare unto Jacob in Padanaram, with his daughter Dinah: all the souls of his sons and his daughters were thirty and three.'); -INSERT INTO t1(docid,words) VALUES(1046016,'And the sons of Gad; Ziphion, and Haggi, Shuni, and Ezbon, Eri, and Arodi, and Areli.'); -INSERT INTO t1(docid,words) VALUES(1046017,'And the sons of Asher; Jimnah, and Ishuah, and Isui, and Beriah, and Serah their sister: and the sons of Beriah; Heber, and Malchiel.'); -INSERT INTO t1(docid,words) VALUES(1046018,'These are the sons of Zilpah, whom Laban gave to Leah his daughter, and these she bare unto Jacob, even sixteen souls.'); -INSERT INTO t1(docid,words) VALUES(1046019,'The sons of Rachel Jacob''s wife; Joseph, and Benjamin.'); -INSERT INTO t1(docid,words) VALUES(1046020,'And unto Joseph in the land of Egypt were born Manasseh and Ephraim, which Asenath the daughter of Potipherah priest of On bare unto him.'); -INSERT INTO t1(docid,words) VALUES(1046021,'And the sons of Benjamin were Belah, and Becher, and Ashbel, Gera, and Naaman, Ehi, and Rosh, Muppim, and Huppim, and Ard.'); -INSERT INTO t1(docid,words) VALUES(1046022,'These are the sons of Rachel, which were born to Jacob: all the souls were fourteen.'); -INSERT INTO t1(docid,words) VALUES(1046023,'And the sons of Dan; Hushim.'); -INSERT INTO t1(docid,words) VALUES(1046024,'And the sons of Naphtali; Jahzeel, and Guni, and Jezer, and Shillem.'); -INSERT INTO t1(docid,words) VALUES(1046025,'These are the sons of Bilhah, which Laban gave unto Rachel his daughter, and she bare these unto Jacob: all the souls were seven.'); -INSERT INTO t1(docid,words) VALUES(1046026,'All the souls that came with Jacob into Egypt, which came out of his loins, besides Jacob''s sons'' wives, all the souls were threescore and six;'); -INSERT INTO t1(docid,words) VALUES(1046027,'And the sons of Joseph, which were born him in Egypt, were two souls: all the souls of the house of Jacob, which came into Egypt, were threescore and ten.'); -INSERT INTO t1(docid,words) VALUES(1046028,'And he sent Judah before him unto Joseph, to direct his face unto Goshen; and they came into the land of Goshen.'); -INSERT INTO t1(docid,words) VALUES(1046029,'And Joseph made ready his chariot, and went up to meet Israel his father, to Goshen, and presented himself unto him; and he fell on his neck, and wept on his neck a good while.'); -INSERT INTO t1(docid,words) VALUES(1046030,'And Israel said unto Joseph, Now let me die, since I have seen thy face, because thou art yet alive.'); -INSERT INTO t1(docid,words) VALUES(1046031,'And Joseph said unto his brethren, and unto his father''s house, I will go up, and shew Pharaoh, and say unto him, My brethren, and my father''s house, which were in the land of Canaan, are come unto me;'); -INSERT INTO t1(docid,words) VALUES(1046032,'And the men are shepherds, for their trade hath been to feed cattle; and they have brought their flocks, and their herds, and all that they have.'); -INSERT INTO t1(docid,words) VALUES(1046033,'And it shall come to pass, when Pharaoh shall call you, and shall say, What is your occupation?'); -INSERT INTO t1(docid,words) VALUES(1046034,'That ye shall say, Thy servants'' trade hath been about cattle from our youth even until now, both we, and also our fathers: that ye may dwell in the land of Goshen; for every shepherd is an abomination unto the Egyptians.'); -INSERT INTO t1(docid,words) VALUES(1047001,'Then Joseph came and told Pharaoh, and said, My father and my brethren, and their flocks, and their herds, and all that they have, are come out of the land of Canaan; and, behold, they are in the land of Goshen.'); -INSERT INTO t1(docid,words) VALUES(1047002,'And he took some of his brethren, even five men, and presented them unto Pharaoh.'); -INSERT INTO t1(docid,words) VALUES(1047003,'And Pharaoh said unto his brethren, What is your occupation? And they said unto Pharaoh, Thy servants are shepherds, both we, and also our fathers.'); -INSERT INTO t1(docid,words) VALUES(1047004,'They said morever unto Pharaoh, For to sojourn in the land are we come; for thy servants have no pasture for their flocks; for the famine is sore in the land of Canaan: now therefore, we pray thee, let thy servants dwell in the land of Goshen.'); -INSERT INTO t1(docid,words) VALUES(1047005,'And Pharaoh spake unto Joseph, saying, Thy father and thy brethren are come unto thee:'); -INSERT INTO t1(docid,words) VALUES(1047006,'The land of Egypt is before thee; in the best of the land make thy father and brethren to dwell; in the land of Goshen let them dwell: and if thou knowest any men of activity among them, then make them rulers over my cattle.'); -INSERT INTO t1(docid,words) VALUES(1047007,'And Joseph brought in Jacob his father, and set him before Pharaoh: and Jacob blessed Pharaoh.'); -INSERT INTO t1(docid,words) VALUES(1047008,'And Pharaoh said unto Jacob, How old art thou?'); -INSERT INTO t1(docid,words) VALUES(1047009,'And Jacob said unto Pharaoh, The days of the years of my pilgrimage are an hundred and thirty years: few and evil have the days of the years of my life been, and have not attained unto the days of the years of the life of my fathers in the days of their pilgrimage.'); -INSERT INTO t1(docid,words) VALUES(1047010,'And Jacob blessed Pharaoh, and went out from before Pharaoh.'); -INSERT INTO t1(docid,words) VALUES(1047011,'And Joseph placed his father and his brethren, and gave them a possession in the land of Egypt, in the best of the land, in the land of Rameses, as Pharaoh had commanded.'); -INSERT INTO t1(docid,words) VALUES(1047012,'And Joseph nourished his father, and his brethren, and all his father''s household, with bread, according to their families.'); -INSERT INTO t1(docid,words) VALUES(1047013,'And there was no bread in all the land; for the famine was very sore, so that the land of Egypt and all the land of Canaan fainted by reason of the famine.'); -INSERT INTO t1(docid,words) VALUES(1047014,'And Joseph gathered up all the money that was found in the land of Egypt, and in the land of Canaan, for the corn which they bought: and Joseph brought the money into Pharaoh''s house.'); -INSERT INTO t1(docid,words) VALUES(1047015,'And when money failed in the land of Egypt, and in the land of Canaan, all the Egyptians came unto Joseph, and said, Give us bread: for why should we die in thy presence? for the money faileth.'); -INSERT INTO t1(docid,words) VALUES(1047016,'And Joseph said, Give your cattle; and I will give you for your cattle, if money fail.'); -INSERT INTO t1(docid,words) VALUES(1047017,'And they brought their cattle unto Joseph: and Joseph gave them bread in exchange for horses, and for the flocks, and for the cattle of the herds, and for the asses: and he fed them with bread for all their cattle for that year.'); -INSERT INTO t1(docid,words) VALUES(1047018,'When that year was ended, they came unto him the second year, and said unto him, We will not hide it from my lord, how that our money is spent; my lord also hath our herds of cattle; there is not ought left in the sight of my lord, but our bodies, and our lands:'); -INSERT INTO t1(docid,words) VALUES(1047019,'Wherefore shall we die before thine eyes, both we and our land? buy us and our land for bread, and we and our land will be servants unto Pharaoh: and give us seed, that we may live, and not die, that the land be not desolate.'); -INSERT INTO t1(docid,words) VALUES(1047020,'And Joseph bought all the land of Egypt for Pharaoh; for the Egyptians sold every man his field, because the famine prevailed over them: so the land became Pharaoh''s.'); -INSERT INTO t1(docid,words) VALUES(1047021,'And as for the people, he removed them to cities from one end of the borders of Egypt even to the other end thereof.'); -INSERT INTO t1(docid,words) VALUES(1047022,'Only the land of the priests bought he not; for the priests had a portion assigned them of Pharaoh, and did eat their portion which Pharaoh gave them: wherefore they sold not their lands.'); -INSERT INTO t1(docid,words) VALUES(1047023,'Then Joseph said unto the people, Behold, I have bought you this day and your land for Pharaoh: lo, here is seed for you, and ye shall sow the land.'); -INSERT INTO t1(docid,words) VALUES(1047024,'And it shall come to pass in the increase, that ye shall give the fifth part unto Pharaoh, and four parts shall be your own, for seed of the field, and for your food, and for them of your households, and for food for your little ones.'); -INSERT INTO t1(docid,words) VALUES(1047025,'And they said, Thou hast saved our lives: let us find grace in the sight of my lord, and we will be Pharaoh''s servants.'); -INSERT INTO t1(docid,words) VALUES(1047026,'And Joseph made it a law over the land of Egypt unto this day, that Pharaoh should have the fifth part, except the land of the priests only, which became not Pharaoh''s.'); -INSERT INTO t1(docid,words) VALUES(1047027,'And Israel dwelt in the land of Egypt, in the country of Goshen; and they had possessions therein, and grew, and multiplied exceedingly.'); -INSERT INTO t1(docid,words) VALUES(1047028,'And Jacob lived in the land of Egypt seventeen years: so the whole age of Jacob was an hundred forty and seven years.'); -INSERT INTO t1(docid,words) VALUES(1047029,'And the time drew nigh that Israel must die: and he called his son Joseph, and said unto him, If now I have found grace in thy sight, put, I pray thee, thy hand under my thigh, and deal kindly and truly with me; bury me not, I pray thee, in Egypt:'); -INSERT INTO t1(docid,words) VALUES(1047030,'But I will lie with my fathers, and thou shalt carry me out of Egypt, and bury me in their buryingplace. And he said, I will do as thou hast said.'); -INSERT INTO t1(docid,words) VALUES(1047031,'And he said, Swear unto me. And he sware unto him. And Israel bowed himself upon the bed''s head.'); -INSERT INTO t1(docid,words) VALUES(1048001,'And it came to pass after these things, that one told Joseph, Behold, thy father is sick: and he took with him his two sons, Manasseh and Ephraim.'); -INSERT INTO t1(docid,words) VALUES(1048002,'And one told Jacob, and said, Behold, thy son Joseph cometh unto thee: and Israel strengthened himself, and sat upon the bed.'); -INSERT INTO t1(docid,words) VALUES(1048003,'And Jacob said unto Joseph, God Almighty appeared unto me at Luz in the land of Canaan, and blessed me,'); -INSERT INTO t1(docid,words) VALUES(1048004,'And said unto me, Behold, I will make thee fruitful, and multiply thee, and I will make of thee a multitude of people; and will give this land to thy seed after thee for an everlasting possession.'); -INSERT INTO t1(docid,words) VALUES(1048005,'And now thy two sons, Ephraim and Manasseh, which were born unto thee in the land of Egypt before I came unto thee into Egypt, are mine; as Reuben and Simeon, they shall be mine.'); -INSERT INTO t1(docid,words) VALUES(1048006,'And thy issue, which thou begettest after them, shall be thine, and shall be called after the name of their brethren in their inheritance.'); -INSERT INTO t1(docid,words) VALUES(1048007,'And as for me, when I came from Padan, Rachel died by me in the land of Canaan in the way, when yet there was but a little way to come unto Ephrath: and I buried her there in the way of Ephrath; the same is Bethlehem.'); -INSERT INTO t1(docid,words) VALUES(1048008,'And Israel beheld Joseph''s sons, and said, Who are these?'); -INSERT INTO t1(docid,words) VALUES(1048009,'And Joseph said unto his father, They are my sons, whom God hath given me in this place. And he said, Bring them, I pray thee, unto me, and I will bless them.'); -INSERT INTO t1(docid,words) VALUES(1048010,'Now the eyes of Israel were dim for age, so that he could not see. And he brought them near unto him; and he kissed them, and embraced them.'); -INSERT INTO t1(docid,words) VALUES(1048011,'And Israel said unto Joseph, I had not thought to see thy face: and, lo, God hath shewed me also thy seed.'); -INSERT INTO t1(docid,words) VALUES(1048012,'And Joseph brought them out from between his knees, and he bowed himself with his face to the earth.'); -INSERT INTO t1(docid,words) VALUES(1048013,'And Joseph took them both, Ephraim in his right hand toward Israel''s left hand, and Manasseh in his left hand toward Israel''s right hand, and brought them near unto him.'); -INSERT INTO t1(docid,words) VALUES(1048014,'And Israel stretched out his right hand, and laid it upon Ephraim''s head, who was the younger, and his left hand upon Manasseh''s head, guiding his hands wittingly; for Manasseh was the firstborn.'); -INSERT INTO t1(docid,words) VALUES(1048015,'And he blessed Joseph, and said, God, before whom my fathers Abraham and Isaac did walk, the God which fed me all my life long unto this day,'); -INSERT INTO t1(docid,words) VALUES(1048016,'The Angel which redeemed me from all evil, bless the lads; and let my name be named on them, and the name of my fathers Abraham and Isaac; and let them grow into a multitude in the midst of the earth.'); -INSERT INTO t1(docid,words) VALUES(1048017,'And when Joseph saw that his father laid his right hand upon the head of Ephraim, it displeased him: and he held up his father''s hand, to remove it from Ephraim''s head unto Manasseh''s head.'); -INSERT INTO t1(docid,words) VALUES(1048018,'And Joseph said unto his father, Not so, my father: for this is the firstborn; put thy right hand upon his head.'); -INSERT INTO t1(docid,words) VALUES(1048019,'And his father refused, and said, I know it, my son, I know it: he also shall become a people, and he also shall be great: but truly his younger brother shall be greater than he, and his seed shall become a multitude of nations.'); -INSERT INTO t1(docid,words) VALUES(1048020,'And he blessed them that day, saying, In thee shall Israel bless, saying, God make thee as Ephraim and as Manasseh: and he set Ephraim before Manasseh.'); -INSERT INTO t1(docid,words) VALUES(1048021,'And Israel said unto Joseph, Behold, I die: but God shall be with you, and bring you again unto the land of your fathers.'); -INSERT INTO t1(docid,words) VALUES(1048022,'Moreover I have given to thee one portion above thy brethren, which I took out of the hand of the Amorite with my sword and with my bow.'); -INSERT INTO t1(docid,words) VALUES(1049001,'And Jacob called unto his sons, and said, Gather yourselves together, that I may tell you that which shall befall you in the last days.'); -INSERT INTO t1(docid,words) VALUES(1049002,'Gather yourselves together, and hear, ye sons of Jacob; and hearken unto Israel your father.'); -INSERT INTO t1(docid,words) VALUES(1049003,'Reuben, thou art my firstborn, my might, and the beginning of my strength, the excellency of dignity, and the excellency of power:'); -INSERT INTO t1(docid,words) VALUES(1049004,'Unstable as water, thou shalt not excel; because thou wentest up to thy father''s bed; then defiledst thou it: he went up to my couch.'); -INSERT INTO t1(docid,words) VALUES(1049005,'Simeon and Levi are brethren; instruments of cruelty are in their habitations.'); -INSERT INTO t1(docid,words) VALUES(1049006,'O my soul, come not thou into their secret; unto their assembly, mine honour, be not thou united: for in their anger they slew a man, and in their selfwill they digged down a wall.'); -INSERT INTO t1(docid,words) VALUES(1049007,'Cursed be their anger, for it was fierce; and their wrath, for it was cruel: I will divide them in Jacob, and scatter them in Israel.'); -INSERT INTO t1(docid,words) VALUES(1049008,'Judah, thou art he whom thy brethren shall praise: thy hand shall be in the neck of thine enemies; thy father''s children shall bow down before thee.'); -INSERT INTO t1(docid,words) VALUES(1049009,'Judah is a lion''s whelp: from the prey, my son, thou art gone up: he stooped down, he couched as a lion, and as an old lion; who shall rouse him up?'); -INSERT INTO t1(docid,words) VALUES(1049010,'The sceptre shall not depart from Judah, nor a lawgiver from between his feet, until Shiloh come; and unto him shall the gathering of the people be.'); -INSERT INTO t1(docid,words) VALUES(1049011,'Binding his foal unto the vine, and his ass''s colt unto the choice vine; he washed his garments in wine, and his clothes in the blood of grapes:'); -INSERT INTO t1(docid,words) VALUES(1049012,'His eyes shall be red with wine, and his teeth white with milk.'); -INSERT INTO t1(docid,words) VALUES(1049013,'Zebulun shall dwell at the haven of the sea; and he shall be for an haven of ships; and his border shall be unto Zidon.'); -INSERT INTO t1(docid,words) VALUES(1049014,'Issachar is a strong ass couching down between two burdens:'); -INSERT INTO t1(docid,words) VALUES(1049015,'And he saw that rest was good, and the land that it was pleasant; and bowed his shoulder to bear, and became a servant unto tribute.'); -INSERT INTO t1(docid,words) VALUES(1049016,'Dan shall judge his people, as one of the tribes of Israel.'); -INSERT INTO t1(docid,words) VALUES(1049017,'Dan shall be a serpent by the way, an adder in the path, that biteth the horse heels, so that his rider shall fall backward.'); -INSERT INTO t1(docid,words) VALUES(1049018,'I have waited for thy salvation, O LORD.'); -INSERT INTO t1(docid,words) VALUES(1049019,'Gad, a troop shall overcome him: but he shall overcome at the last.'); -INSERT INTO t1(docid,words) VALUES(1049020,'Out of Asher his bread shall be fat, and he shall yield royal dainties.'); -INSERT INTO t1(docid,words) VALUES(1049021,'Naphtali is a hind let loose: he giveth goodly words.'); -INSERT INTO t1(docid,words) VALUES(1049022,'Joseph is a fruitful bough, even a fruitful bough by a well; whose branches run over the wall:'); -INSERT INTO t1(docid,words) VALUES(1049023,'The archers have sorely grieved him, and shot at him, and hated him:'); -INSERT INTO t1(docid,words) VALUES(1049024,'But his bow abode in strength, and the arms of his hands were made strong by the hands of the mighty God of Jacob; (from thence is the shepherd, the stone of Israel:)'); -INSERT INTO t1(docid,words) VALUES(1049025,'Even by the God of thy father, who shall help thee; and by the Almighty, who shall bless thee with blessings of heaven above, blessings of the deep that lieth under, blessings of the breasts, and of the womb:'); -INSERT INTO t1(docid,words) VALUES(1049026,'The blessings of thy father have prevailed above the blessings of my progenitors unto the utmost bound of the everlasting hills: they shall be on the head of Joseph, and on the crown of the head of him that was separate from his brethren.'); -INSERT INTO t1(docid,words) VALUES(1049027,'Benjamin shall ravin as a wolf: in the morning he shall devour the prey, and at night he shall divide the spoil.'); -INSERT INTO t1(docid,words) VALUES(1049028,'All these are the twelve tribes of Israel: and this is it that their father spake unto them, and blessed them; every one according to his blessing he blessed them.'); -INSERT INTO t1(docid,words) VALUES(1049029,'And he charged them, and said unto them, I am to be gathered unto my people: bury me with my fathers in the cave that is in the field of Ephron the Hittite,'); -INSERT INTO t1(docid,words) VALUES(1049030,'In the cave that is in the field of Machpelah, which is before Mamre, in the land of Canaan, which Abraham bought with the field of Ephron the Hittite for a possession of a buryingplace.'); -INSERT INTO t1(docid,words) VALUES(1049031,'There they buried Abraham and Sarah his wife; there they buried Isaac and Rebekah his wife; and there I buried Leah.'); -INSERT INTO t1(docid,words) VALUES(1049032,'The purchase of the field and of the cave that is therein was from the children of Heth.'); -INSERT INTO t1(docid,words) VALUES(1049033,'And when Jacob had made an end of commanding his sons, he gathered up his feet into the bed, and yielded up the ghost, and was gathered unto his people.'); -INSERT INTO t1(docid,words) VALUES(1050001,'And Joseph fell upon his father''s face, and wept upon him, and kissed him.'); -INSERT INTO t1(docid,words) VALUES(1050002,'And Joseph commanded his servants the physicians to embalm his father: and the physicians embalmed Israel.'); -INSERT INTO t1(docid,words) VALUES(1050003,'And forty days were fulfilled for him; for so are fulfilled the days of those which are embalmed: and the Egyptians mourned for him threescore and ten days.'); -INSERT INTO t1(docid,words) VALUES(1050004,'And when the days of his mourning were past, Joseph spake unto the house of Pharaoh, saying, If now I have found grace in your eyes, speak, I pray you, in the ears of Pharaoh, saying,'); -INSERT INTO t1(docid,words) VALUES(1050005,'My father made me swear, saying, Lo, I die: in my grave which I have digged for me in the land of Canaan, there shalt thou bury me. Now therefore let me go up, I pray thee, and bury my father, and I will come again.'); -INSERT INTO t1(docid,words) VALUES(1050006,'And Pharaoh said, Go up, and bury thy father, according as he made thee swear.'); -INSERT INTO t1(docid,words) VALUES(1050007,'And Joseph went up to bury his father: and with him went up all the servants of Pharaoh, the elders of his house, and all the elders of the land of Egypt,'); -INSERT INTO t1(docid,words) VALUES(1050008,'And all the house of Joseph, and his brethren, and his father''s house: only their little ones, and their flocks, and their herds, they left in the land of Goshen.'); -INSERT INTO t1(docid,words) VALUES(1050009,'And there went up with him both chariots and horsemen: and it was a very great company.'); -INSERT INTO t1(docid,words) VALUES(1050010,'And they came to the threshingfloor of Atad, which is beyond Jordan, and there they mourned with a great and very sore lamentation: and he made a mourning for his father seven days.'); -INSERT INTO t1(docid,words) VALUES(1050011,'And when the inhabitants of the land, the Canaanites, saw the mourning in the floor of Atad, they said, This is a grievous mourning to the Egyptians: wherefore the name of it was called Abelmizraim, which is beyond Jordan.'); -INSERT INTO t1(docid,words) VALUES(1050012,'And his sons did unto him according as he commanded them:'); -INSERT INTO t1(docid,words) VALUES(1050013,'For his sons carried him into the land of Canaan, and buried him in the cave of the field of Machpelah, which Abraham bought with the field for a possession of a buryingplace of Ephron the Hittite, before Mamre.'); -INSERT INTO t1(docid,words) VALUES(1050014,'And Joseph returned into Egypt, he, and his brethren, and all that went up with him to bury his father, after he had buried his father.'); -INSERT INTO t1(docid,words) VALUES(1050015,'And when Joseph''s brethren saw that their father was dead, they said, Joseph will peradventure hate us, and will certainly requite us all the evil which we did unto him.'); -INSERT INTO t1(docid,words) VALUES(1050016,'And they sent a messenger unto Joseph, saying, Thy father did command before he died, saying,'); -INSERT INTO t1(docid,words) VALUES(1050017,'So shall ye say unto Joseph, Forgive, I pray thee now, the trespass of thy brethren, and their sin; for they did unto thee evil: and now, we pray thee, forgive the trespass of the servants of the God of thy father. And Joseph wept when they spake unto him.'); -INSERT INTO t1(docid,words) VALUES(1050018,'And his brethren also went and fell down before his face; and they said, Behold, we be thy servants.'); -INSERT INTO t1(docid,words) VALUES(1050019,'And Joseph said unto them, Fear not: for am I in the place of God?'); -INSERT INTO t1(docid,words) VALUES(1050020,'But as for you, ye thought evil against me; but God meant it unto good, to bring to pass, as it is this day, to save much people alive.'); -INSERT INTO t1(docid,words) VALUES(1050021,'Now therefore fear ye not: I will nourish you, and your little ones. And he comforted them, and spake kindly unto them.'); -INSERT INTO t1(docid,words) VALUES(1050022,'And Joseph dwelt in Egypt, he, and his father''s house: and Joseph lived an hundred and ten years.'); -INSERT INTO t1(docid,words) VALUES(1050023,'And Joseph saw Ephraim''s children of the third generation: the children also of Machir the son of Manasseh were brought up upon Joseph''s knees.'); -INSERT INTO t1(docid,words) VALUES(1050024,'And Joseph said unto his brethren, I die: and God will surely visit you, and bring you out of this land unto the land which he sware to Abraham, to Isaac, and to Jacob.'); -INSERT INTO t1(docid,words) VALUES(1050025,'And Joseph took an oath of the children of Israel, saying, God will surely visit you, and ye shall carry up my bones from hence.'); -INSERT INTO t1(docid,words) VALUES(1050026,'So Joseph died, being an hundred and ten years old: and they embalmed him, and he was put in a coffin in Egypt.'); -COMMIT; -} -} +source $testdir/genesis.tcl # The following is a list of queries to perform against the above # FTS3/FTS4 database. We will be trying these queries in various @@ -1589,7 +51,7 @@ do_test fts4aa-1.0 { db eval { CREATE VIRTUAL TABLE t1 USING fts4(words, tokenize porter); } - fts4aa_fill_table + fts_kjv_genesis foreach q $::fts4aa_queries { set r [db eval {SELECT docid FROM t1 WHERE words MATCH $q ORDER BY docid}] set ::fts4aa_res($q) $r @@ -1673,7 +135,7 @@ do_test fts4aa-2.0 { DROP TABLE t1; CREATE VIRTUAL TABLE t1 USING fts3(words, tokenize porter); } - fts4aa_fill_table + fts_kjv_genesis } {} unset -nocomplain ii set ii 0 @@ -1694,7 +156,7 @@ do_test fts4aa-3.0 { PRAGMA page_size=65536; CREATE VIRTUAL TABLE t1 USING fts4(words, tokenize porter); } - fts4aa_fill_table + fts_kjv_genesis } {} unset -nocomplain ii set ii 0 @@ -1718,7 +180,7 @@ do_test fts4aa-4.0 { DROP TABLE t1; CREATE VIRTUAL TABLE t1 USING fts4(words, tokenize porter); } - fts4aa_fill_table + fts_kjv_genesis } {} unset -nocomplain ii set ii 0 diff --git a/test/fts4check.test b/test/fts4check.test index cc1d018..c98886c 100644 --- a/test/fts4check.test +++ b/test/fts4check.test @@ -152,4 +152,32 @@ foreach {tn disruption} { do_execsql_test 3.2.3.$tn "ROLLBACK" } +#-------------------------------------------------------------------------- +# Test case 4.* +# +# Test that the integrity-check works if there are "notindexed" columns. +# +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t4 USING fts4(a, b, c, notindexed=b); + INSERT INTO t4 VALUES('text one', 'text two', 'text three'); + INSERT INTO t4(t4) VALUES('integrity-check'); +} + +do_execsql_test 4.1 { + PRAGMA writable_schema = 1; + UPDATE sqlite_master + SET sql = 'CREATE VIRTUAL TABLE t4 USING fts4(a, b, c)' + WHERE name = 't4'; +} + +do_test 4.2 { + db close + sqlite3 db test.db + catchsql { + INSERT INTO t4(t4) VALUES('integrity-check'); + } +} {1 {database disk image is malformed}} +reset_db + finish_test + diff --git a/test/fts4content.test b/test/fts4content.test index 302f14e..6b2cd3c 100644 --- a/test/fts4content.test +++ b/test/fts4content.test @@ -623,4 +623,3 @@ do_execsql_test 10.7 { } finish_test - diff --git a/test/fts4docid.test b/test/fts4docid.test new file mode 100644 index 0000000..2328b6e --- /dev/null +++ b/test/fts4docid.test @@ -0,0 +1,116 @@ +# 2012 March 26 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/fts3_common.tcl +set ::testprefix fts4docid + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +# Initialize a table with pseudo-randomly generated data. +# +do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts4; } +do_test 1.1 { + foreach {docid content} { + 0 {F N K B T I K V B A} 1 {D M J E S P H E L O} + 2 {W U T Q T Q T L H G} 3 {D W H M B R S Z B K} + 4 {F Q I N P Q J L Z D} 5 {J O Q E Y A O E L B} + 6 {O V R A C R K C Y H} 7 {Z J H T Q Q O R A G} + 8 {L K J W G D Y W B M} 9 {K E Y I A Q R Q T S} + 10 {N P H Y Z M R T I C} 11 {E X H O I S E S Z F} + 12 {B Y Q T J X C L L J} 13 {Q D C U U A Q E Z U} + 14 {S I T C J R X S J M} 15 {M X M K E X L H Q Y} + 16 {O W E I C H U Y S Y} 17 {P V V E M T H C C S} + 18 {L Y A M I E N M X O} 19 {S Y R U L S Q Y F P} + 20 {U J S T T J J S V X} 21 {T E I W P O V A A P} + 22 {W D K H D H F G O J} 23 {T X Y P G M J U I L} + 24 {F V X E B C N B K W} 25 {E B A Y N N T Z I C} + 26 {G E E B C P U D H G} 27 {J D J K N S B Q T M} + 28 {Q T G M D O D Y V G} 29 {P X W I W V P W Z G} + } { + execsql { INSERT INTO t1(docid, content) VALUES($docid, $content) } + } +} {} + +# Quick test regarding affinites and the docid/rowid column. +do_execsql_test 2.1.1 { SELECT docid FROM t1 WHERE docid = 5 } {5} +do_execsql_test 2.1.2 { SELECT docid FROM t1 WHERE docid = '5' } {5} +do_execsql_test 2.1.3 { SELECT docid FROM t1 WHERE docid = +5 } {5} +do_execsql_test 2.1.4 { SELECT docid FROM t1 WHERE docid = +'5' } {5} +do_execsql_test 2.1.5 { SELECT docid FROM t1 WHERE docid < 5 } {0 1 2 3 4} +do_execsql_test 2.1.6 { SELECT docid FROM t1 WHERE docid < '5' } {0 1 2 3 4} + +do_execsql_test 2.2.1 { SELECT rowid FROM t1 WHERE rowid = 5 } {5} +do_execsql_test 2.2.2 { SELECT rowid FROM t1 WHERE rowid = '5' } {5} +do_execsql_test 2.2.3 { SELECT rowid FROM t1 WHERE rowid = +5 } {5} +do_execsql_test 2.2.4 { SELECT rowid FROM t1 WHERE rowid = +'5' } {5} +do_execsql_test 2.2.5 { SELECT rowid FROM t1 WHERE rowid < 5 } {0 1 2 3 4} +do_execsql_test 2.2.6 { SELECT rowid FROM t1 WHERE rowid < '5' } {0 1 2 3 4} + +#------------------------------------------------------------------------- +# Now test a bunch of full-text queries featuring range constraints on +# the docid field. Each query is run so that the range constraint: +# +# * is on the docid field, +# * is on the docid field with a unary +, +# * is on the rowid field, +# * is on the rowid field with a unary +. +# +# Queries are run with both "ORDER BY docid DESC" and "ORDER BY docid ASC" +# clauses. +# +foreach {tn where result} { + 1 {WHERE t1 MATCH 'O' AND xxx < 17} {1 5 6 7 11 16} + 2 {WHERE t1 MATCH 'O' AND xxx < 4123456789123456} {1 5 6 7 11 16 18 21 22 28} + 3 {WHERE t1 MATCH 'O' AND xxx < 1} {} + 4 {WHERE t1 MATCH 'O' AND xxx < -4123456789123456} {} + + 5 {WHERE t1 MATCH 'O' AND xxx > 17} {18 21 22 28} + 6 {WHERE t1 MATCH 'O' AND xxx > 4123456789123456} {} + 7 {WHERE t1 MATCH 'O' AND xxx > 1} {5 6 7 11 16 18 21 22 28} + 8 {WHERE t1 MATCH 'O' AND xxx > -4123456789123456} {1 5 6 7 11 16 18 21 22 28} + + 9 {WHERE t1 MATCH '"Q T"' AND xxx < 27} {2 9 12} + 10 {WHERE t1 MATCH '"Q T"' AND xxx <= 27} {2 9 12 27} + 11 {WHERE t1 MATCH '"Q T"' AND xxx > 27} {28} + 12 {WHERE t1 MATCH '"Q T"' AND xxx >= 27} {27 28} +} { + foreach {tn2 ref order} { + 1 docid "ORDER BY docid ASC" + 2 +docid "ORDER BY docid ASC" + 3 rowid "ORDER BY docid ASC" + 4 +rowid "ORDER BY docid ASC" + + 5 docid "ORDER BY docid DESC" + 6 +docid "ORDER BY docid DESC" + 7 rowid "ORDER BY docid DESC" + 8 +rowid "ORDER BY docid DESC" + } { + set w [string map "xxx $ref" $where] + set q "SELECT docid FROM t1 $w $order" + + if {$tn2<5} { + set r [lsort -integer -increasing $result] + } else { + set r [lsort -integer -decreasing $result] + } + + do_execsql_test 3.$tn.$tn2 $q $r + } +} + +finish_test diff --git a/test/fts4growth.test b/test/fts4growth.test new file mode 100644 index 0000000..aa5f251 --- /dev/null +++ b/test/fts4growth.test @@ -0,0 +1,437 @@ +# 2014 May 12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS4 module. +# +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fts4growth + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +source $testdir/genesis.tcl + +do_execsql_test 1.1 { CREATE VIRTUAL TABLE x1 USING fts3; } + +do_test 1.2 { + foreach L { + {"See here, young man," said Mulga Bill, "from Walgett to the sea,} + {From Conroy's Gap to Castlereagh, there's none can ride like me.} + {I'm good all round at everything as everybody knows,} + {Although I'm not the one to talk -- I hate a man that blows.} + } { + execsql { INSERT INTO x1 VALUES($L) } + } + execsql { SELECT end_block, length(root) FROM x1_segdir } +} {{0 114} 114 {0 118} 118 {0 95} 95 {0 115} 115} + +do_execsql_test 1.3 { + INSERT INTO x1(x1) VALUES('optimize'); + SELECT level, end_block, length(root) FROM x1_segdir; +} {0 {0 394} 394} + +do_test 1.4 { + foreach L { + {But riding is my special gift, my chiefest, sole delight;} + {Just ask a wild duck can it swim, a wildcat can it fight.} + {There's nothing clothed in hair or hide, or built of flesh or steel,} + {There's nothing walks or jumps, or runs, on axle, hoof, or wheel,} + {But what I'll sit, while hide will hold and girths and straps are tight:} + {I'll ride this here two-wheeled concern right straight away at sight."} + } { + execsql { INSERT INTO x1 VALUES($L) } + } + execsql { + INSERT INTO x1(x1) VALUES('merge=4,4'); + SELECT level, end_block, length(root) FROM x1_segdir; + } +} {0 {0 110} 110 0 {0 132} 132 0 {0 129} 129 1 {128 658} 2} + +do_execsql_test 1.5 { + SELECT length(block) FROM x1_segments; +} {658 {}} + +do_test 1.6 { + foreach L { + {'Twas Mulga Bill, from Eaglehawk, that sought his own abode,} + {That perched above Dead Man's Creek, beside the mountain road.} + {He turned the cycle down the hill and mounted for the fray,} + {But 'ere he'd gone a dozen yards it bolted clean away.} + {It left the track, and through the trees, just like a silver steak,} + {It whistled down the awful slope towards the Dead Man's Creek.} + {It shaved a stump by half an inch, it dodged a big white-box:} + {The very wallaroos in fright went scrambling up the rocks,} + {The wombats hiding in their caves dug deeper underground,} + {As Mulga Bill, as white as chalk, sat tight to every bound.} + {It struck a stone and gave a spring that cleared a fallen tree,} + {It raced beside a precipice as close as close could be;} + {And then as Mulga Bill let out one last despairing shriek} + {It made a leap of twenty feet into the Dead Man's Creek.} + } { + execsql { INSERT INTO x1 VALUES($L) } + } + execsql { + SELECT level, end_block, length(root) FROM x1_segdir; + } +} {1 {128 658} 2 1 {130 1377} 6 0 {0 117} 117} + +do_execsql_test 1.7 { + SELECT sum(length(block)) FROM x1_segments WHERE blockid IN (129, 130); +} {1377} + +#------------------------------------------------------------------------- +# +do_execsql_test 2.1 { + CREATE TABLE t1(docid, words); + CREATE VIRTUAL TABLE x2 USING fts4; +} +fts_kjv_genesis +do_test 2.2 { + foreach id [db eval {SELECT docid FROM t1}] { + execsql { + INSERT INTO x2(docid, content) SELECT $id, words FROM t1 WHERE docid=$id + } + } + foreach id [db eval {SELECT docid FROM t1}] { + execsql { + INSERT INTO x2(docid, content) SELECT NULL, words FROM t1 WHERE docid=$id + } + if {[db one {SELECT count(*) FROM x2_segdir WHERE level<2}]==2} break + } +} {} + +do_execsql_test 2.3 { + SELECT count(*) FROM x2_segdir WHERE level=2; + SELECT count(*) FROM x2_segdir WHERE level=3; +} {6 0} + +do_execsql_test 2.4 { + INSERT INTO x2(x2) VALUES('merge=4,4'); + SELECT count(*) FROM x2_segdir WHERE level=2; + SELECT count(*) FROM x2_segdir WHERE level=3; +} {6 1} + +do_execsql_test 2.5 { + SELECT end_block FROM x2_segdir WHERE level=3; + INSERT INTO x2(x2) VALUES('merge=4,4'); + SELECT end_block FROM x2_segdir WHERE level=3; + INSERT INTO x2(x2) VALUES('merge=4,4'); + SELECT end_block FROM x2_segdir WHERE level=3; +} {{3828 -3430} {3828 -10191} {3828 -14109}} + +do_execsql_test 2.6 { + SELECT sum(length(block)) FROM x2_segdir, x2_segments WHERE + blockid BETWEEN start_block AND leaves_end_block + AND level=3 +} {14109} + +do_execsql_test 2.7 { + INSERT INTO x2(x2) VALUES('merge=1000,4'); + SELECT end_block FROM x2_segdir WHERE level=3; +} {{3828 86120}} + +do_execsql_test 2.8 { + SELECT sum(length(block)) FROM x2_segdir, x2_segments WHERE + blockid BETWEEN start_block AND leaves_end_block + AND level=3 +} {86120} + +#-------------------------------------------------------------------------- +# Test that delete markers are removed from FTS segments when possible. +# It is only possible to remove delete markers when the output of the +# merge operation will become the oldest segment in the index. +# +# 3.1 - when the oldest segment is created by an 'optimize'. +# 3.2 - when the oldest segment is created by an incremental merge. +# 3.3 - by a crisis merge. +# + +proc insert_doc {args} { + foreach iDoc $args { + set L [lindex { + {In your eagerness to engage the Trojans,} + {don’t any of you charge ahead of others,} + {trusting in your strength and horsemanship.} + {And don’t lag behind. That will hurt our charge.} + {Any man whose chariot confronts an enemy’s} + {should thrust with his spear at him from there.} + {That’s the most effective tactic, the way} + {men wiped out city strongholds long ago —} + {their chests full of that style and spirit.} + } [expr $iDoc%9]] + execsql { REPLACE INTO x3(docid, content) VALUES($iDoc, $L) } + } +} + +proc delete_doc {args} { + foreach iDoc $args { + execsql { DELETE FROM x3 WHERE docid = $iDoc } + } +} + +proc second {x} { lindex $x 1 } +db func second second + +do_execsql_test 3.0 { CREATE VIRTUAL TABLE x3 USING fts4 } + +do_test 3.1.1 { + db transaction { insert_doc 1 2 3 4 5 6 } + execsql { SELECT level, idx, second(end_block) FROM x3_segdir } +} {0 0 412} +do_test 3.1.2 { + delete_doc 1 2 3 4 5 6 + execsql { SELECT count(*) FROM x3_segdir } +} {0} +do_test 3.1.3 { + db transaction { + insert_doc 1 2 3 4 5 6 7 8 9 + delete_doc 9 8 7 + } + execsql { SELECT level, idx, second(end_block) FROM x3_segdir } +} {0 0 591 0 1 65 0 2 72 0 3 76} +do_test 3.1.4 { + execsql { INSERT INTO x3(x3) VALUES('optimize') } + execsql { SELECT level, idx, second(end_block) FROM x3_segdir } +} {0 0 412} + +do_test 3.2.1 { + execsql { DELETE FROM x3 } + insert_doc 8 7 6 5 4 3 2 1 + delete_doc 7 8 + execsql { SELECT count(*) FROM x3_segdir } +} {10} +do_test 3.2.2 { + execsql { INSERT INTO x3(x3) VALUES('merge=500,10') } + execsql { SELECT level, idx, second(end_block) FROM x3_segdir } +} {1 0 412} + +# This assumes the crisis merge happens when there are already 16 +# segments and one more is added. +# +do_test 3.3.1 { + execsql { DELETE FROM x3 } + insert_doc 1 2 3 4 5 6 7 8 9 10 11 + delete_doc 11 10 9 8 7 + execsql { SELECT count(*) FROM x3_segdir } +} {16} + +do_test 3.3.2 { + insert_doc 12 + execsql { SELECT level, idx, second(end_block) FROM x3_segdir WHERE level=1 } +} {1 0 412} + +#-------------------------------------------------------------------------- +# Check a theory on a bug in fts4 - that segments with idx==0 were not +# being incrementally merged correctly. Theory turned out to be false. +# +do_execsql_test 4.1 { + DROP TABLE IF EXISTS x4; + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(docid, words); + CREATE VIRTUAL TABLE x4 USING fts4(words); +} +do_test 4.2 { + fts_kjv_genesis + execsql { INSERT INTO x4 SELECT words FROM t1 } + execsql { INSERT INTO x4 SELECT words FROM t1 } +} {} + +do_execsql_test 4.3 { + SELECT level, idx, second(end_block) FROM x4_segdir +} {0 0 117483 0 1 118006} + +do_execsql_test 4.4 { + INSERT INTO x4(x4) VALUES('merge=10,2'); + SELECT count(*) FROM x4_segdir; +} {3} + +do_execsql_test 4.5 { + INSERT INTO x4(x4) VALUES('merge=10,2'); + SELECT count(*) FROM x4_segdir; +} {3} + +do_execsql_test 4.6 { + INSERT INTO x4(x4) VALUES('merge=1000,2'); + SELECT count(*) FROM x4_segdir; +} {1} + + + +#-------------------------------------------------------------------------- +# Check that segments are not promoted if the "end_block" field does not +# contain a size. +# +do_execsql_test 5.1 { + DROP TABLE IF EXISTS x2; + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(docid, words); + CREATE VIRTUAL TABLE x2 USING fts4; +} +fts_kjv_genesis + +proc first {L} {lindex $L 0} +db func first first + +do_test 5.2 { + foreach r [db eval { SELECT rowid FROM t1 }] { + execsql { + INSERT INTO x2(docid, content) SELECT docid, words FROM t1 WHERE rowid=$r + } + } + foreach d [db eval { SELECT docid FROM t1 LIMIT -1 OFFSET 20 }] { + execsql { DELETE FROM x2 WHERE docid = $d } + } + + execsql { + INSERT INTO x2(x2) VALUES('optimize'); + SELECT level, idx, end_block FROM x2_segdir + } +} {2 0 {752 1926}} + +do_execsql_test 5.3 { + UPDATE x2_segdir SET end_block = CAST( first(end_block) AS INTEGER ); + SELECT end_block, typeof(end_block) FROM x2_segdir; +} {752 integer} + +do_execsql_test 5.4 { + INSERT INTO x2 SELECT words FROM t1 LIMIT 50; + SELECT level, idx, end_block FROM x2_segdir +} {2 0 752 0 0 {758 5174}} + +do_execsql_test 5.5 { + UPDATE x2_segdir SET end_block = end_block || ' 1926' WHERE level=2; + INSERT INTO x2 SELECT words FROM t1 LIMIT 40; + SELECT level, idx, end_block FROM x2_segdir +} {0 0 {752 1926} 0 1 {758 5174} 0 2 {763 4170}} + +proc t1_to_x2 {} { + foreach id [db eval {SELECT docid FROM t1 LIMIT 2}] { + execsql { + DELETE FROM x2 WHERE docid=$id; + INSERT INTO x2(docid, content) SELECT $id, words FROM t1 WHERE docid=$id; + } + } +} + +#-------------------------------------------------------------------------- +# Check that segments created by auto-merge are not promoted until they +# are completed. +# + +do_execsql_test 6.1 { + CREATE VIRTUAL TABLE x5 USING fts4; + INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 0; + INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 25; + INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 50; + INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 75; + SELECT count(*) FROM x5_segdir +} {4} + +do_execsql_test 6.2 { + INSERT INTO x5(x5) VALUES('merge=2,4'); + SELECT level, idx, end_block FROM x5_segdir; +} {0 0 {10 9216} 0 1 {21 9330} 0 2 {31 8850} 0 3 {40 8689} 1 0 {1320 -3117}} + +do_execsql_test 6.3 { + INSERT INTO x5 SELECT words FROM t1 LIMIT 100 OFFSET 100; + SELECT level, idx, end_block FROM x5_segdir; +} { + 0 0 {10 9216} 0 1 {21 9330} 0 2 {31 8850} + 0 3 {40 8689} 1 0 {1320 -3117} 0 4 {1329 8297} +} + +do_execsql_test 6.4 { + INSERT INTO x5(x5) VALUES('merge=200,4'); + SELECT level, idx, end_block FROM x5_segdir; +} {0 0 {1329 8297} 1 0 {1320 28009}} + +do_execsql_test 6.5 { + INSERT INTO x5 SELECT words FROM t1; + SELECT level, idx, end_block FROM x5_segdir; +} { + 0 1 {1329 8297} 0 0 {1320 28009} 0 2 {1449 118006} +} + +#-------------------------------------------------------------------------- +# Ensure that if part of an incremental merge is performed by an old +# version that does not support storing segment sizes in the end_block +# field, no size is stored in the final segment (as it would be incorrect). +# +do_execsql_test 7.1 { + CREATE VIRTUAL TABLE x6 USING fts4; + INSERT INTO x6 SELECT words FROM t1; + INSERT INTO x6 SELECT words FROM t1; + INSERT INTO x6 SELECT words FROM t1; + INSERT INTO x6 SELECT words FROM t1; + INSERT INTO x6 SELECT words FROM t1; + INSERT INTO x6 SELECT words FROM t1; + SELECT level, idx, end_block FROM x6_segdir; +} { + 0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006} + 0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006} +} + +do_execsql_test 7.2 { + INSERT INTO x6(x6) VALUES('merge=25,4'); + SELECT level, idx, end_block FROM x6_segdir; +} { + 0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006} + 0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006} + 1 0 {16014 -51226} +} + +do_execsql_test 7.3 { + UPDATE x6_segdir SET end_block = first(end_block) WHERE level=1; + SELECT level, idx, end_block FROM x6_segdir; +} { + 0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006} + 0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006} + 1 0 16014 +} + +do_execsql_test 7.4 { + INSERT INTO x6(x6) VALUES('merge=25,4'); + SELECT level, idx, end_block FROM x6_segdir; +} { + 0 0 {118 117483} 0 1 {238 118006} 0 2 {358 118006} + 0 3 {478 118006} 0 4 {598 118006} 0 5 {718 118006} + 1 0 16014 +} + +do_execsql_test 7.5 { + INSERT INTO x6(x6) VALUES('merge=2500,4'); + SELECT level, idx, end_block FROM x6_segdir; +} { + 0 0 {598 118006} 0 1 {718 118006} 1 0 16014 +} + +do_execsql_test 7.6 { + INSERT INTO x6(x6) VALUES('merge=2500,2'); + SELECT level, idx, start_block, leaves_end_block, end_block FROM x6_segdir; +} { + 2 0 23695 24147 {41262 633507} +} + +do_execsql_test 7.7 { + SELECT sum(length(block)) FROM x6_segments + WHERE blockid BETWEEN 23695 AND 24147 +} {633507} + + + +finish_test + diff --git a/test/fts4growth2.test b/test/fts4growth2.test new file mode 100644 index 0000000..af41d51 --- /dev/null +++ b/test/fts4growth2.test @@ -0,0 +1,93 @@ +# 2014 May 12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS4 module. +# +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fts4growth2 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +source $testdir/genesis.tcl + +do_execsql_test 1.0 { CREATE TABLE t1(docid, words); } +fts_kjv_genesis + +proc structure {} { + puts [ db eval {SELECT level, count(*) FROM x1_segdir GROUP BY level} ] +} + +proc tt {val} { + execsql { + DELETE FROM x1 + WHERE docid IN (SELECT docid FROM t1 WHERE (rowid-1)%4==$val+0); + } + execsql { + INSERT INTO x1(docid, content) + SELECT docid, words FROM t1 WHERE (rowid%4)==$val+0; + } +} + +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE x1 USING fts4; + INSERT INTO x1(x1) VALUES('automerge=2'); +} + +do_test 1.2 { + for {set i 0} {$i < 40} {incr i} { + tt 0 ; tt 1 ; tt 2 ; tt 3 + } + execsql { + SELECT max(level) FROM x1_segdir; + SELECT count(*) FROM x1_segdir WHERE level=2; + } +} {2 1} + +do_test 1.3 { + for {set i 0} {$i < 40} {incr i} { + tt 0 ; tt 1 ; tt 2 ; tt 3 + } + execsql { + SELECT max(level) FROM x1_segdir; + SELECT count(*) FROM x1_segdir WHERE level=2; + } +} {2 1} + +#------------------------------------------------------------------------- +# +do_execsql_test 2.1 { + DELETE FROM t1 WHERE rowid>16; + DROP TABLE IF EXISTS x1; + CREATE VIRTUAL TABLE x1 USING fts4; +} + +db func second second +proc second {L} {lindex $L 1} + +for {set tn 0} {$tn < 40} {incr tn} { + do_test 2.2.$tn { + for {set i 0} {$i < 100} {incr i} { + tt 0 ; tt 1 ; tt 2 ; tt 3 + } + execsql { SELECT max(level) FROM x1_segdir } + } {1} +} + + +finish_test + diff --git a/test/fts4incr.test b/test/fts4incr.test new file mode 100644 index 0000000..17212ef --- /dev/null +++ b/test/fts4incr.test @@ -0,0 +1,75 @@ +# 2012 March 26 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/fts3_common.tcl +set ::testprefix fts4incr + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +# Create the fts_kjv_genesis procedure which fills and FTS3/4 table +# with the complete text of the Book of Genesis. +# +source $testdir/genesis.tcl + +do_test 1.0 { + execsql { CREATE VIRTUAL TABLE t1 USING fts4(words) } + fts_kjv_genesis +} {} + +do_execsql_test 1.1 { + SELECT min(docid), max(docid) FROM t1; +} {1001001 1050026} + +foreach {tn q res} { + 1 { SELECT count(*) FROM t1 WHERE t1 MATCH 'and' AND docid < 1010000} 224 + 2 { SELECT count(*) FROM t1 WHERE t1 MATCH '"in the"' AND docid < 1010000} 47 + 3 { SELECT count(*) FROM t1 WHERE t1 MATCH '"And God"' AND docid < 1010000} 33 + 4 { SELECT count(*) FROM t1 WHERE t1 + MATCH '"land of canaan"' AND docid < 1030000 } 7 +} { + foreach s {0 1} { + execsql "INSERT INTO t1(t1) VALUES('test-no-incr-doclist=$s')" + do_execsql_test 2.$tn.$s $q $res + set t($s) [lindex [time [list execsql $q] 100] 0] + } + puts "with optimization: $t(0) without: $t(1)" +} + +do_test 2.1 { + execsql { + CREATE VIRTUAL TABLE t2 USING fts4(order=DESC); + } + set num [list one two three four five six seven eight nine ten] + execsql BEGIN + for {set i 0} {$i < 10000} {incr i} { + set x "[lindex $num [expr $i%10]] zero" + execsql { INSERT INTO t2(docid, content) VALUES($i, $x) } + } + execsql COMMIT + execsql { INSERT INTO t2(t2) VALUES('optimize') } +} {} + +do_execsql_test 2.2 { + SELECT count(*) FROM t2 WHERE t2 MATCH '"never zero"' +} {0} + +do_execsql_test 2.3 { + SELECT count(*) FROM t2 WHERE t2 MATCH '"two zero"' +} {1000} + +finish_test diff --git a/test/fts4merge4.test b/test/fts4merge4.test new file mode 100644 index 0000000..038e460 --- /dev/null +++ b/test/fts4merge4.test @@ -0,0 +1,102 @@ +# 2013 May 29 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/fts3_common.tcl +set ::testprefix fts4merge4 + +ifcapable !fts3 { + finish_test + return +} + +set ::enable_shared_cache [sqlite3_enable_shared_cache 1] + +do_execsql_test 1.1 { CREATE VIRTUAL TABLE t1 USING fts4 } + +do_test 1.2 { + for {set i 0} {$i < 2000} {incr i} { + execsql {INSERT INTO t1 VALUES('a b c d e f g h i j k l');} + } +} {} + +do_test 1.3 { + execsql BEGIN + for {set i 0} {$i < 2000} {incr i} { + execsql {INSERT INTO t1 VALUES('a b c d e f g h i j k l');} + } + execsql { + INSERT INTO t1(t1) VALUES('merge=8,50'); + COMMIT + } +} {} + +reset_db +do_execsql_test 2.0 { CREATE VIRTUAL TABLE t1 USING fts4 } +do_test 2.1 { + for {set i 0} {$i < 2000} {incr i} { + execsql {INSERT INTO t1 VALUES('a b c d e f g h i j k l');} + } +} {} +do_execsql_test 2.2 { SELECT count(*) FROM t1_segdir; } 35 +do_execsql_test 2.3 { INSERT INTO t1(t1) VALUES('optimize') } {} +do_execsql_test 2.4 { SELECT count(*) FROM t1_segdir; } 1 + +#------------------------------------------------------------------------- +# Now test that the automerge=? option appears to work. +# +do_execsql_test 2.1 { CREATE VIRTUAL TABLE t2 USING fts4; } + +set doc "" +foreach c1 "a b c d e f g h i j" { + foreach c2 "a b c d e f g h i j" { + foreach c3 "a b c d e f g h i j" { + lappend doc "$c1$c2$c3" + } + } +} +set doc [string repeat $doc 10] + +foreach {tn am expected} { + 1 {automerge=2} {1 1 2 1 4 1 6 1} + 2 {automerge=4} {1 2 2 1 3 1} + 3 {automerge=8} {0 4 1 3 2 1} + 4 {automerge=1} {0 4 1 3 2 1} +} { + foreach {tn2 openclose} {1 {} 2 { db close ; sqlite3 db test.db }} { + do_test 2.2.$tn.$tn2 { + execsql { DELETE FROM t2 } + execsql { INSERT INTO t2(t2) VALUES($am) }; + + eval $openclose + + for {set i 0} {$i < 100} {incr i} { + execsql { + BEGIN; + INSERT INTO t2 VALUES($doc); + INSERT INTO t2 VALUES($doc); + INSERT INTO t2 VALUES($doc); + INSERT INTO t2 VALUES($doc); + INSERT INTO t2 VALUES($doc); + COMMIT; + } + } + + execsql { SELECT level, count(*) FROM t2_segdir GROUP BY level } + } [list {*}$expected] + } +} + +sqlite3_enable_shared_cache $::enable_shared_cache +finish_test diff --git a/test/fts4noti.test b/test/fts4noti.test new file mode 100644 index 0000000..c90999b --- /dev/null +++ b/test/fts4noti.test @@ -0,0 +1,233 @@ +# 2013 June 21 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the notindexed=xxx FTS4 option. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix fts4noti + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + + +#------------------------------------------------------------------------- +# Test that typos in "notindexed=" column names are detected. +# +do_execsql_test 1.0 { + CREATE TABLE cc(a, b, c); +} +foreach {tn arg res} { + 1 "(b, c, notindexed=a)" {1 {no such column: a}} + 2 "(a, b, notindexed=a)" {0 {}} + 3 "(a, b, notindexed=a, notindexed=a)" {0 {}} + 4 "(notindexed=a, a, b)" {0 {}} + 5 "(notindexed=a, notindexed=b, notindexed=c, a, b, c, d)" {0 {}} + 6 "(notindexed=a, notindexed=B, notindexed=c, a, b, c, d)" {0 {}} + 7 "(notindexed=a, notindexed=b, notindexed=c, a, B, c, d)" {0 {}} + 8 "(notindexed=d, content=cc)" {1 {no such column: d}} + 9 "(notindexed=a, content=cc)" {0 {}} + 10 "(notindexed=a, notindexed=b, a)" {1 {no such column: b}} + 11 "(notindexed=a, notindexed=b, b)" {1 {no such column: a}} +} { + do_catchsql_test 1.$tn "CREATE VIRTUAL TABLE t1 USING fts4 $arg" $res + if {[lindex $res 0]==0} { execsql "DROP TABLE t1" } +} + +do_execsql_test 1.x { SELECT name FROM sqlite_master } {cc} + + +#------------------------------------------------------------------------- +# Test that notindexed columns are not indexed. +# +foreach {tn schema} { + 1 { + CREATE VIRTUAL TABLE t1 USING fts4(a, b, c, notindexed=b); + } + 2 { + CREATE TABLE c1(a, b, c); + INSERT INTO c1 VALUES('one two', 'three four', 'five six'); + INSERT INTO c1 VALUES('three four', 'five six', 'one two'); + CREATE VIRTUAL TABLE t1 USING fts4(content=c1, notindexed=b); + } + 3 { + CREATE VIRTUAL TABLE t1 USING fts4(content="", a, b, c, notindexed=b); + } +} { + execsql $schema + + do_execsql_test 2.$tn.1 { + INSERT INTO t1(docid,a,b,c) VALUES(1, 'one two', 'three four', 'five six'); + INSERT INTO t1(docid,a,b,c) VALUES(2, 'three four', 'five six', 'one two'); + } + + do_execsql_test 2.$tn.2 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} + do_execsql_test 2.$tn.3 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} + do_execsql_test 2.$tn.4 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} + + do_execsql_test 2.$tn.5 { INSERT INTO t1(t1) VALUES('optimize') } + + do_execsql_test 2.$tn.6 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} + do_execsql_test 2.$tn.7 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} + do_execsql_test 2.$tn.8 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} + + if {$tn!=3} { + do_execsql_test 2.$tn.9 { INSERT INTO t1(t1) VALUES('rebuild') } + + do_execsql_test 2.$tn.10 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} + do_execsql_test 2.$tn.11 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} + do_execsql_test 2.$tn.12 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} + + do_execsql_test 2.$tn.13 { + SELECT a,b,c FROM t1 WHERE docid=1 + } {{one two} {three four} {five six}} + do_execsql_test 2.$tn.14 { + SELECT a,b,c FROM t1 WHERE docid=2 + } {{three four} {five six} {one two}} + } + + do_execsql_test 2.x { DROP TABLE t1 } +} + +#------------------------------------------------------------------------- +# Test that notindexed columns are not scanned for deferred tokens. +# + +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE t2 USING fts4(x, y, notindexed=x); +} +do_test 3.2 { + set v [string repeat " 1" 50000] + set v1 "x $v" + set v2 "y $v" + execsql { + INSERT INTO t2 VALUES(1, 'x y z'); + INSERT INTO t2 VALUES(2, $v1); + INSERT INTO t2 VALUES(3, $v2); + INSERT INTO t2 VALUES(4, $v2); + INSERT INTO t2 VALUES(5, $v2); + INSERT INTO t2 VALUES(6, $v2); + } +} {} + +do_execsql_test 3.3 { SELECT x FROM t2 WHERE t2 MATCH '2' } {} +do_execsql_test 3.4 { SELECT x FROM t2 WHERE t2 MATCH '1' } {2 3 4 5 6} +do_execsql_test 3.5 { SELECT x FROM t2 WHERE t2 MATCH 'x' } {1 2} +do_execsql_test 3.6 { SELECT x FROM t2 WHERE t2 MATCH 'x 1' } {2} + +do_execsql_test 3.x { DROP TABLE t2 } + +#------------------------------------------------------------------------- +# Test that the types of notindexed columns are not modified. +# +do_execsql_test 4.1 { + CREATE VIRTUAL TABLE t2 USING fts4(poi, addr, notindexed=poi); + INSERT INTO t2 VALUES(114, 'x x x'); + INSERT INTO t2 VALUES(X'1234', 'y y y'); + INSERT INTO t2 VALUES(NULL, 'z z z'); + INSERT INTO t2 VALUES(113.2, 'w w w'); + INSERT INTO t2 VALUES('poi', 'v v v'); +} +do_execsql_test 4.2 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'x' } {integer} +do_execsql_test 4.3 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'y' } {blob} +do_execsql_test 4.4 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'z' } {null} +do_execsql_test 4.5 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'w' } {real} +do_execsql_test 4.6 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'v' } {text} + +do_execsql_test 4.x { DROP TABLE t2 } + +#------------------------------------------------------------------------- +# Test that multiple notindexed options on a single table work as expected. +# +do_execsql_test 5.1 { + CREATE VIRTUAL TABLE t2 USING fts4( + notindexed="three", one, two, three, notindexed="one", + ); + INSERT INTO t2 VALUES('a', 'b', 'c'); + INSERT INTO t2 VALUES('c', 'a', 'b'); + INSERT INTO t2 VALUES('b', 'c', 'a'); +} +do_execsql_test 5.2 { SELECT docid FROM t2 WHERE t2 MATCH 'a' } {2} +do_execsql_test 5.3 { SELECT docid FROM t2 WHERE t2 MATCH 'b' } {1} +do_execsql_test 5.4 { SELECT docid FROM t2 WHERE t2 MATCH 'c' } {3} + +do_execsql_test 5.x { DROP TABLE t2 } + +#------------------------------------------------------------------------- +# Check that if an indexed column name is a prefix of a notindexed column +# name, the column is still correctly tokenized. This was a problem at one +# point. +do_execsql_test 6.1.1 { + CREATE VIRTUAL TABLE t1 USING fts4( + poiCategory, poiCategoryId, notindexed=poiCategoryId + ); + INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021); +} + +do_execsql_test 6.1.2 { + SELECT * FROM t1 WHERE t1 MATCH 'restaurant'; +} { Restaurant 6021 } +do_execsql_test 6.1.3 { + SELECT * FROM t1 WHERE t1 MATCH 're*'; +} { Restaurant 6021 } +do_execsql_test 6.1.4 { + SELECT * FROM t1 WHERE t1 MATCH '6021'; +} {} +do_execsql_test 6.1.5 { + SELECT * FROM t1 WHERE t1 MATCH '60*'; +} {} + +do_execsql_test 6.2.1 { + DROP TABLE t1; + CREATE VIRTUAL TABLE t1 USING fts4( + poiCategory, poiCategoryId, notindexed=poiCategory + ); + INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021); +} + +do_execsql_test 6.2.2 { + SELECT * FROM t1 WHERE t1 MATCH 'restaurant'; +} {} +do_execsql_test 6.2.3 { + SELECT * FROM t1 WHERE t1 MATCH 're*'; +} {} +do_execsql_test 6.2.4 { + SELECT * FROM t1 WHERE t1 MATCH '6021'; +} { Restaurant 6021 } +do_execsql_test 6.2.5 { + SELECT * FROM t1 WHERE t1 MATCH '60*'; +} { Restaurant 6021 } + +do_execsql_test 6.3.1 { + DROP TABLE t1; + CREATE VIRTUAL TABLE t1 USING fts4(abc, ab, a, notindexed=abc); + CREATE VIRTUAL TABLE t2 USING fts4(a, ab, abc, notindexed=abc); + + INSERT INTO t1 VALUES('no', 'yes', 'yep'); + INSERT INTO t2 VALUES('yep', 'yes', 'no'); + + SELECT count(*) FROM t1 WHERE t1 MATCH 'no'; + SELECT count(*) FROM t1 WHERE t1 MATCH 'yes'; + SELECT count(*) FROM t1 WHERE t1 MATCH 'yep'; + + SELECT count(*) FROM t2 WHERE t2 MATCH 'no'; + SELECT count(*) FROM t2 WHERE t2 MATCH 'yes'; + SELECT count(*) FROM t2 WHERE t2 MATCH 'yep'; +} {0 1 1 0 1 1} + +finish_test + + + diff --git a/test/fts4unicode.test b/test/fts4unicode.test index 8bd83f6..f237119 100644 --- a/test/fts4unicode.test +++ b/test/fts4unicode.test @@ -44,31 +44,36 @@ proc do_unicode_token_test3 {tn args} { } do_unicode_token_test 1.0 {a B c D} {0 a a 1 b B 2 c c 3 d D} -do_unicode_token_test 1.1 {Ä Ö Ü} {0 ä Ä 1 ö Ö 2 ü Ü} -do_unicode_token_test 1.2 {xÄx xÖx xÜx} {0 xäx xÄx 1 xöx xÖx 2 xüx xÜx} + +do_unicode_token_test 1.1 "\uC4 \uD6 \uDC" \ + "0 \uE4 \uC4 1 \uF6 \uD6 2 \uFC \uDC" + +do_unicode_token_test 1.2 "x\uC4x x\uD6x x\uDCx" \ + "0 x\uE4x x\uC4x 1 x\uF6x x\uD6x 2 x\uFCx x\uDCx" # 0x00DF is a small "sharp s". 0x1E9E is a capital sharp s. do_unicode_token_test 1.3 "\uDF" "0 \uDF \uDF" -do_unicode_token_test 1.4 "\u1E9E" "0 ß \u1E9E" -do_unicode_token_test 1.5 "\u1E9E" "0 \uDF \u1E9E" +do_unicode_token_test 1.4 "\u1E9E" "0 \uDF \u1E9E" -do_unicode_token_test 1.6 "The quick brown fox" { +do_unicode_token_test 1.5 "The quick brown fox" { 0 the The 1 quick quick 2 brown brown 3 fox fox } -do_unicode_token_test 1.7 "The\u00bfquick\u224ebrown\u2263fox" { +do_unicode_token_test 1.6 "The\u00bfquick\u224ebrown\u2263fox" { 0 the The 1 quick quick 2 brown brown 3 fox fox } -do_unicode_token_test2 1.8 {a B c D} {0 a a 1 b B 2 c c 3 d D} -do_unicode_token_test2 1.9 {Ä Ö Ü} {0 a Ä 1 o Ö 2 u Ü} -do_unicode_token_test2 1.10 {xÄx xÖx xÜx} {0 xax xÄx 1 xox xÖx 2 xux xÜx} +do_unicode_token_test2 1.7 {a B c D} {0 a a 1 b B 2 c c 3 d D} +do_unicode_token_test2 1.8 "\uC4 \uD6 \uDC" "0 a \uC4 1 o \uD6 2 u \uDC" + +do_unicode_token_test2 1.9 "x\uC4x x\uD6x x\uDCx" \ + "0 xax x\uC4x 1 xox x\uD6x 2 xux x\uDCx" # Check that diacritics are removed if remove_diacritics=1 is specified. # And that they do not break tokens. -do_unicode_token_test2 1.11 "xx\u0301xx" "0 xxxx xx\u301xx" +do_unicode_token_test2 1.10 "xx\u0301xx" "0 xxxx xx\u301xx" # Title-case mappings work -do_unicode_token_test 1.12 "\u01c5" "0 \u01c6 \u01c5" +do_unicode_token_test 1.11 "\u01c5" "0 \u01c6 \u01c5" #------------------------------------------------------------------------- # @@ -378,11 +383,176 @@ foreach T $tokenizers { do_isspace_test 6.$T.18 $T 12288 do_isspace_test 6.$T.19 $T {32 160 5760 6158} - do_isspace_test 6.$T.19 $T {8192 8193 8194 8195} - do_isspace_test 6.$T.19 $T {8196 8197 8198 8199} - do_isspace_test 6.$T.19 $T {8200 8201 8202 8239} - do_isspace_test 6.$T.19 $T {8287 12288} + do_isspace_test 6.$T.20 $T {8192 8193 8194 8195} + do_isspace_test 6.$T.21 $T {8196 8197 8198 8199} + do_isspace_test 6.$T.22 $T {8200 8201 8202 8239} + do_isspace_test 6.$T.23 $T {8287 12288} +} + +#------------------------------------------------------------------------- +# Test that the private use ranges are treated as alphanumeric. +# +foreach {tn1 c} { + 1 \ue000 2 \ue001 3 \uf000 4 \uf8fe 5 \uf8ff +} { + foreach {tn2 config res} { + 1 "" "0 hello*world hello*world" + 2 "separators=*" "0 hello hello 1 world world" + } { + set config [string map [list * $c] $config] + set input [string map [list * $c] "hello*world"] + set output [string map [list * $c] $res] + do_unicode_token_test3 7.$tn1.$tn2 {*}$config $input $output + } +} + +#------------------------------------------------------------------------- +# Cursory test of remove_diacritics=0. +# +# 00C4;LATIN CAPITAL LETTER A WITH DIAERESIS +# 00D6;LATIN CAPITAL LETTER O WITH DIAERESIS +# 00E4;LATIN SMALL LETTER A WITH DIAERESIS +# 00F6;LATIN SMALL LETTER O WITH DIAERESIS +# +do_execsql_test 8.1.1 " + CREATE VIRTUAL TABLE t3 USING fts4(tokenize=unicode61 'remove_diacritics=1'); + INSERT INTO t3 VALUES('o'); + INSERT INTO t3 VALUES('a'); + INSERT INTO t3 VALUES('O'); + INSERT INTO t3 VALUES('A'); + INSERT INTO t3 VALUES('\xD6'); + INSERT INTO t3 VALUES('\xC4'); + INSERT INTO t3 VALUES('\xF6'); + INSERT INTO t3 VALUES('\xE4'); +" +do_execsql_test 8.1.2 { + SELECT rowid FROM t3 WHERE t3 MATCH 'o'; +} {1 3 5 7} +do_execsql_test 8.1.3 { + SELECT rowid FROM t3 WHERE t3 MATCH 'a'; +} {2 4 6 8} +do_execsql_test 8.2.1 { + CREATE VIRTUAL TABLE t4 USING fts4(tokenize=unicode61 "remove_diacritics=0"); + INSERT INTO t4 SELECT * FROM t3; +} +do_execsql_test 8.2.2 { + SELECT rowid FROM t4 WHERE t4 MATCH 'o'; +} {1 3} +do_execsql_test 8.2.3 { + SELECT rowid FROM t4 WHERE t4 MATCH 'a'; +} {2 4} + +#------------------------------------------------------------------------- +# +foreach {tn sql} { + 1 { + CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 [tokenchars= .]); + CREATE VIRTUAL TABLE t6 USING fts4( + tokenize=unicode61 [tokenchars=="] "tokenchars=[]"); + CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 [separators=x\xC4]); + } + 2 { + CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 "tokenchars= ."); + CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 "tokenchars=[=""]"); + CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 "separators=x\xC4"); + } + 3 { + CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 'tokenchars= .'); + CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 'tokenchars=="[]'); + CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 'separators=x\xC4'); + } + 4 { + CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 `tokenchars= .`); + CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 `tokenchars=[="]`); + CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 `separators=x\xC4`); + } +} { + do_execsql_test 9.$tn.0 { + DROP TABLE IF EXISTS t5; + DROP TABLE IF EXISTS t5aux; + DROP TABLE IF EXISTS t6; + DROP TABLE IF EXISTS t6aux; + DROP TABLE IF EXISTS t7; + DROP TABLE IF EXISTS t7aux; + } + do_execsql_test 9.$tn.1 $sql + + do_execsql_test 9.$tn.2 { + CREATE VIRTUAL TABLE t5aux USING fts4aux(t5); + INSERT INTO t5 VALUES('one two three/four.five.six'); + SELECT * FROM t5aux; + } { + four.five.six * 1 1 four.five.six 0 1 1 + {one two three} * 1 1 {one two three} 0 1 1 + } + + do_execsql_test 9.$tn.3 { + CREATE VIRTUAL TABLE t6aux USING fts4aux(t6); + INSERT INTO t6 VALUES('alpha=beta"gamma/delta[epsilon]zeta'); + SELECT * FROM t6aux; + } { + {alpha=beta"gamma} * 1 1 {alpha=beta"gamma} 0 1 1 + {delta[epsilon]zeta} * 1 1 {delta[epsilon]zeta} 0 1 1 + } + + do_execsql_test 9.$tn.4 { + CREATE VIRTUAL TABLE t7aux USING fts4aux(t7); + INSERT INTO t7 VALUES('alephxbeth\xC4gimel'); + SELECT * FROM t7aux; + } { + aleph * 1 1 aleph 0 1 1 + beth * 1 1 beth 0 1 1 + gimel * 1 1 gimel 0 1 1 + } +} + +# Check that multiple options are handled correctly. +# +do_execsql_test 10.1 { + DROP TABLE IF EXISTS t1; + CREATE VIRTUAL TABLE t1 USING fts4(tokenize=unicode61 + "tokenchars=xyz" "tokenchars=.=" "separators=.=" "separators=xy" + "separators=a" "separators=a" "tokenchars=a" "tokenchars=a" + ); + + INSERT INTO t1 VALUES('oneatwoxthreeyfour'); + INSERT INTO t1 VALUES('a.single=word'); + CREATE VIRTUAL TABLE t1aux USING fts4aux(t1); + SELECT * FROM t1aux; +} { + .single=word * 1 1 .single=word 0 1 1 + four * 1 1 four 0 1 1 + one * 1 1 one 0 1 1 + three * 1 1 three 0 1 1 + two * 1 1 two 0 1 1 +} + +# Test that case folding happens after tokenization, not before. +# +do_execsql_test 10.2 { + DROP TABLE IF EXISTS t2; + CREATE VIRTUAL TABLE t2 USING fts4(tokenize=unicode61 "separators=aB"); + INSERT INTO t2 VALUES('oneatwoBthree'); + INSERT INTO t2 VALUES('onebtwoAthree'); + CREATE VIRTUAL TABLE t2aux USING fts4aux(t2); + SELECT * FROM t2aux; +} { + one * 1 1 one 0 1 1 + onebtwoathree * 1 1 onebtwoathree 0 1 1 + three * 1 1 three 0 1 1 + two * 1 1 two 0 1 1 } +# Test that the tokenchars and separators options work with the +# fts3tokenize table. +# +do_execsql_test 11.1 { + CREATE VIRTUAL TABLE ft1 USING fts3tokenize( + "unicode61", "tokenchars=@.", "separators=1234567890" + ); + SELECT token FROM ft1 WHERE input = 'berlin@street123sydney.road'; +} { + berlin@street sydney.road +} finish_test diff --git a/test/func.test b/test/func.test index 4ab7688..98ae8dd 100644 --- a/test/func.test +++ b/test/func.test @@ -14,6 +14,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix func # Create a table to work with. # @@ -682,6 +683,32 @@ do_test func-13.7 { lappend res [sqlite3_finalize $STMT] } {{0 0} {1 0} SQLITE_OK} +# Test that auxiliary data is discarded when a statement is reset. +do_execsql_test 13.8.1 { + SELECT test_auxdata('constant') FROM t4; +} {0 1} +do_execsql_test 13.8.2 { + SELECT test_auxdata('constant') FROM t4; +} {0 1} +db cache flush +do_execsql_test 13.8.3 { + SELECT test_auxdata('constant') FROM t4; +} {0 1} +set V "one" +do_execsql_test 13.8.4 { + SELECT test_auxdata($V), $V FROM t4; +} {0 one 1 one} +set V "two" +do_execsql_test 13.8.5 { + SELECT test_auxdata($V), $V FROM t4; +} {0 two 1 two} +db cache flush +set V "three" +do_execsql_test 13.8.6 { + SELECT test_auxdata($V), $V FROM t4; +} {0 three 1 three} + + # Make sure that a function with a very long name is rejected do_test func-14.1 { catch { @@ -1167,6 +1194,18 @@ do_test func-24.12 { WHEN 'program' THEN null ELSE t1 END) FROM tbl1 } } {,is,free,software} +# Tests to verify ticket http://www.sqlite.org/src/tktview/55746f9e65f8587c0 +do_test func-24.13 { + execsql { + SELECT typeof(group_concat(x)) FROM (SELECT '' AS x); + } +} {text} +do_test func-24.14 { + execsql { + SELECT typeof(group_concat(x,'')) + FROM (SELECT '' AS x UNION ALL SELECT ''); + } +} {text} # Use the test_isolation function to make sure that type conversions @@ -1274,11 +1313,13 @@ do_test func-29.3 { db eval {SELECT typeof(+x) FROM t29 ORDER BY id} } {integer null real blob text} if {[permutation] != "mmap"} { - do_test func-29.4 { - set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] - if {$x>100} {set x many} - set x - } {many} + ifcapable !direct_read { + do_test func-29.4 { + set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] + if {$x>100} {set x many} + set x + } {many} + } } do_test func-29.5 { db close @@ -1292,6 +1333,32 @@ do_test func-29.6 { set x } {1} +# The OP_Column opcode has an optimization that avoids loading content +# for fields with content-length=0 when the content offset is on an overflow +# page. Make sure the optimization works. +# +do_execsql_test func-29.10 { + CREATE TABLE t29b(a,b,c,d,e,f,g,h,i); + INSERT INTO t29b + VALUES(1, hex(randomblob(2000)), null, 0, 1, '', zeroblob(0),'x',x'01'); + SELECT typeof(c), typeof(d), typeof(e), typeof(f), + typeof(g), typeof(h), typeof(i) FROM t29b; +} {null integer integer text blob text blob} +do_execsql_test func-29.11 { + SELECT length(f), length(g), length(h), length(i) FROM t29b; +} {0 0 1 1} +do_execsql_test func-29.12 { + SELECT quote(f), quote(g), quote(h), quote(i) FROM t29b; +} {'' X'' 'x' X'01'} + +# EVIDENCE-OF: R-29701-50711 The unicode(X) function returns the numeric +# unicode code point corresponding to the first character of the string +# X. +# +# EVIDENCE-OF: R-55469-62130 The char(X1,X2,...,XN) function returns a +# string composed of characters having the unicode code point values of +# integers X1 through XN, respectively. +# do_execsql_test func-30.1 {SELECT unicode('$');} 36 do_execsql_test func-30.2 [subst {SELECT unicode('\u00A2');}] 162 do_execsql_test func-30.3 [subst {SELECT unicode('\u20AC');}] 8364 @@ -1308,4 +1375,9 @@ for {set i 65536} {$i<=0x10ffff} {incr i 139} { do_execsql_test func-30.5.$i {SELECT unicode(char($i))} $i } +# Test char(). +# +do_execsql_test func-31.1 { + SELECT char(), length(char()), typeof(char()) +} {{} 0 text} finish_test diff --git a/test/func3.test b/test/func3.test index d5a462f..3b1613b 100644 --- a/test/func3.test +++ b/test/func3.test @@ -70,4 +70,121 @@ do_test func3-4.1 { } {1 SQLITE_MISUSE} do_test func3-4.2 { set destroyed } 1 +# EVIDENCE-OF: R-41921-05214 The likelihood(X,Y) function returns +# argument X unchanged. +# +do_execsql_test func3-5.1 { + SELECT likelihood(9223372036854775807, 0.5); +} {9223372036854775807} +do_execsql_test func3-5.2 { + SELECT likelihood(-9223372036854775808, 0.5); +} {-9223372036854775808} +do_execsql_test func3-5.3 { + SELECT likelihood(14.125, 0.5); +} {14.125} +do_execsql_test func3-5.4 { + SELECT likelihood(NULL, 0.5); +} {{}} +do_execsql_test func3-5.5 { + SELECT likelihood('test-string', 0.5); +} {test-string} +do_execsql_test func3-5.6 { + SELECT quote(likelihood(x'010203000405', 0.5)); +} {X'010203000405'} + +# EVIDENCE-OF: R-44133-61651 The value Y in likelihood(X,Y) must be a +# floating point constant between 0.0 and 1.0, inclusive. +# +do_execsql_test func3-5.7 { + SELECT likelihood(123, 1.0), likelihood(456, 0.0); +} {123 456} +do_test func3-5.8 { + catchsql { + SELECT likelihood(123, 1.000001); + } +} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}} +do_test func3-5.9 { + catchsql { + SELECT likelihood(123, -0.000001); + } +} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}} +do_test func3-5.10 { + catchsql { + SELECT likelihood(123, 0.5+0.3); + } +} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}} + +# EVIDENCE-OF: R-28535-44631 The likelihood(X) function is a no-op that +# the code generator optimizes away so that it consumes no CPU cycles +# during run-time (that is, during calls to sqlite3_step()). +# +do_test func3-5.20 { + db eval {EXPLAIN SELECT likelihood(min(1.0+'2.0',4*11), 0.5)} +} [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] + + +# EVIDENCE-OF: R-11152-23456 The unlikely(X) function returns the +# argument X unchanged. +# +do_execsql_test func3-5.30 { + SELECT unlikely(9223372036854775807); +} {9223372036854775807} +do_execsql_test func3-5.31 { + SELECT unlikely(-9223372036854775808); +} {-9223372036854775808} +do_execsql_test func3-5.32 { + SELECT unlikely(14.125); +} {14.125} +do_execsql_test func3-5.33 { + SELECT unlikely(NULL); +} {{}} +do_execsql_test func3-5.34 { + SELECT unlikely('test-string'); +} {test-string} +do_execsql_test func3-5.35 { + SELECT quote(unlikely(x'010203000405')); +} {X'010203000405'} + +# EVIDENCE-OF: R-22887-63324 The unlikely(X) function is a no-op that +# the code generator optimizes away so that it consumes no CPU cycles at +# run-time (that is, during calls to sqlite3_step()). +# +do_test func3-5.39 { + db eval {EXPLAIN SELECT unlikely(min(1.0+'2.0',4*11))} +} [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] + + +# EVIDENCE-OF: R-23735-03107 The likely(X) function returns the argument +# X unchanged. +# +do_execsql_test func3-5.50 { + SELECT likely(9223372036854775807); +} {9223372036854775807} +do_execsql_test func3-5.51 { + SELECT likely(-9223372036854775808); +} {-9223372036854775808} +do_execsql_test func3-5.52 { + SELECT likely(14.125); +} {14.125} +do_execsql_test func3-5.53 { + SELECT likely(NULL); +} {{}} +do_execsql_test func3-5.54 { + SELECT likely('test-string'); +} {test-string} +do_execsql_test func3-5.55 { + SELECT quote(likely(x'010203000405')); +} {X'010203000405'} + +# EVIDENCE-OF: R-43464-09689 The likely(X) function is a no-op that the +# code generator optimizes away so that it consumes no CPU cycles at +# run-time (that is, during calls to sqlite3_step()). +# +do_test func3-5.59 { + db eval {EXPLAIN SELECT likely(min(1.0+'2.0',4*11))} +} [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] + + + + finish_test diff --git a/test/func4.test b/test/func4.test new file mode 100644 index 0000000..e94f8c3 --- /dev/null +++ b/test/func4.test @@ -0,0 +1,758 @@ +# 2013 March 10 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The focus of +# this file is testing the tointeger() and toreal() functions. +# +# Several of the toreal() tests are disabled on platforms where floating +# point precision is not high enough to represent their constant integer +# expression arguments as double precision floating point values. +# +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set saved_tcl_precision $tcl_precision +set tcl_precision 0 +load_static_extension db totype + +set highPrecision(1) [expr \ + {[db eval {SELECT tointeger(9223372036854775807 + 1);}] eq {{}}}] + +do_execsql_test func4-1.1 { + SELECT tointeger(NULL); +} {{}} +do_execsql_test func4-1.2 { + SELECT tointeger(''); +} {{}} +do_execsql_test func4-1.3 { + SELECT tointeger(' '); +} {{}} +do_execsql_test func4-1.4 { + SELECT tointeger('1234'); +} {1234} +do_execsql_test func4-1.5 { + SELECT tointeger(' 1234'); +} {{}} +do_execsql_test func4-1.6 { + SELECT tointeger('bad'); +} {{}} +do_execsql_test func4-1.7 { + SELECT tointeger('0xBAD'); +} {{}} +do_execsql_test func4-1.8 { + SELECT tointeger('123BAD'); +} {{}} +do_execsql_test func4-1.9 { + SELECT tointeger('0x123BAD'); +} {{}} +do_execsql_test func4-1.10 { + SELECT tointeger('123NO'); +} {{}} +do_execsql_test func4-1.11 { + SELECT tointeger('0x123NO'); +} {{}} +do_execsql_test func4-1.12 { + SELECT tointeger('-0x1'); +} {{}} +do_execsql_test func4-1.13 { + SELECT tointeger('-0x0'); +} {{}} +do_execsql_test func4-1.14 { + SELECT tointeger('0x0'); +} {{}} +do_execsql_test func4-1.15 { + SELECT tointeger('0x1'); +} {{}} +do_execsql_test func4-1.16 { + SELECT tointeger(-1); +} {-1} +do_execsql_test func4-1.17 { + SELECT tointeger(-0); +} {0} +do_execsql_test func4-1.18 { + SELECT tointeger(0); +} {0} +do_execsql_test func4-1.19 { + SELECT tointeger(1); +} {1} +do_execsql_test func4-1.20 { + SELECT tointeger(-1.79769313486232e308 - 1); +} {{}} +do_execsql_test func4-1.21 { + SELECT tointeger(-1.79769313486232e308); +} {{}} +do_execsql_test func4-1.22 { + SELECT tointeger(-1.79769313486232e308 + 1); +} {{}} +do_execsql_test func4-1.23 { + SELECT tointeger(-9223372036854775808 - 1); +} {-9223372036854775808} +do_execsql_test func4-1.24 { + SELECT tointeger(-9223372036854775808); +} {-9223372036854775808} +do_execsql_test func4-1.25 { + SELECT tointeger(-9223372036854775808 + 1); +} {-9223372036854775807} +do_execsql_test func4-1.26 { + SELECT tointeger(-9223372036854775807 - 1); +} {-9223372036854775808} +do_execsql_test func4-1.27 { + SELECT tointeger(-9223372036854775807); +} {-9223372036854775807} +do_execsql_test func4-1.28 { + SELECT tointeger(-9223372036854775807 + 1); +} {-9223372036854775806} +do_execsql_test func4-1.29 { + SELECT tointeger(-2147483648 - 1); +} {-2147483649} +do_execsql_test func4-1.30 { + SELECT tointeger(-2147483648); +} {-2147483648} +do_execsql_test func4-1.31 { + SELECT tointeger(-2147483648 + 1); +} {-2147483647} +do_execsql_test func4-1.32 { + SELECT tointeger(2147483647 - 1); +} {2147483646} +do_execsql_test func4-1.33 { + SELECT tointeger(2147483647); +} {2147483647} +do_execsql_test func4-1.34 { + SELECT tointeger(2147483647 + 1); +} {2147483648} +do_execsql_test func4-1.35 { + SELECT tointeger(9223372036854775807 - 1); +} {9223372036854775806} +do_execsql_test func4-1.36 { + SELECT tointeger(9223372036854775807); +} {9223372036854775807} +if {$highPrecision(1)} { + do_execsql_test func4-1.37 { + SELECT tointeger(9223372036854775807 + 1); + } {{}} +} +do_execsql_test func4-1.38 { + SELECT tointeger(1.79769313486232e308 - 1); +} {{}} +do_execsql_test func4-1.39 { + SELECT tointeger(1.79769313486232e308); +} {{}} +do_execsql_test func4-1.40 { + SELECT tointeger(1.79769313486232e308 + 1); +} {{}} +do_execsql_test func4-1.41 { + SELECT tointeger(4503599627370496 - 1); +} {4503599627370495} +do_execsql_test func4-1.42 { + SELECT tointeger(4503599627370496); +} {4503599627370496} +do_execsql_test func4-1.43 { + SELECT tointeger(4503599627370496 + 1); +} {4503599627370497} +do_execsql_test func4-1.44 { + SELECT tointeger(9007199254740992 - 1); +} {9007199254740991} +do_execsql_test func4-1.45 { + SELECT tointeger(9007199254740992); +} {9007199254740992} +do_execsql_test func4-1.46 { + SELECT tointeger(9007199254740992 + 1); +} {9007199254740993} +do_execsql_test func4-1.47 { + SELECT tointeger(9223372036854775807 - 1); +} {9223372036854775806} +do_execsql_test func4-1.48 { + SELECT tointeger(9223372036854775807); +} {9223372036854775807} +if {$highPrecision(1)} { + do_execsql_test func4-1.49 { + SELECT tointeger(9223372036854775807 + 1); + } {{}} + do_execsql_test func4-1.50 { + SELECT tointeger(9223372036854775808 - 1); + } {{}} + do_execsql_test func4-1.51 { + SELECT tointeger(9223372036854775808); + } {{}} + do_execsql_test func4-1.52 { + SELECT tointeger(9223372036854775808 + 1); + } {{}} +} +do_execsql_test func4-1.53 { + SELECT tointeger(18446744073709551616 - 1); +} {{}} +do_execsql_test func4-1.54 { + SELECT tointeger(18446744073709551616); +} {{}} +do_execsql_test func4-1.55 { + SELECT tointeger(18446744073709551616 + 1); +} {{}} + +ifcapable floatingpoint { + set highPrecision(2) [expr \ + {[db eval {SELECT toreal(-9223372036854775808 + 1);}] eq {{}}}] + + do_execsql_test func4-2.1 { + SELECT toreal(NULL); + } {{}} + do_execsql_test func4-2.2 { + SELECT toreal(''); + } {{}} + do_execsql_test func4-2.3 { + SELECT toreal(' '); + } {{}} + do_execsql_test func4-2.4 { + SELECT toreal('1234'); + } {1234.0} + do_execsql_test func4-2.5 { + SELECT toreal(' 1234'); + } {{}} + do_execsql_test func4-2.6 { + SELECT toreal('bad'); + } {{}} + do_execsql_test func4-2.7 { + SELECT toreal('0xBAD'); + } {{}} + do_execsql_test func4-2.8 { + SELECT toreal('123BAD'); + } {{}} + do_execsql_test func4-2.9 { + SELECT toreal('0x123BAD'); + } {{}} + do_execsql_test func4-2.10 { + SELECT toreal('123NO'); + } {{}} + do_execsql_test func4-2.11 { + SELECT toreal('0x123NO'); + } {{}} + do_execsql_test func4-2.12 { + SELECT toreal('-0x1'); + } {{}} + do_execsql_test func4-2.13 { + SELECT toreal('-0x0'); + } {{}} + do_execsql_test func4-2.14 { + SELECT toreal('0x0'); + } {{}} + do_execsql_test func4-2.15 { + SELECT toreal('0x1'); + } {{}} + do_execsql_test func4-2.16 { + SELECT toreal(-1); + } {-1.0} + do_execsql_test func4-2.17 { + SELECT toreal(-0); + } {0.0} + do_execsql_test func4-2.18 { + SELECT toreal(0); + } {0.0} + do_execsql_test func4-2.19 { + SELECT toreal(1); + } {1.0} + do_execsql_test func4-2.20 { + SELECT toreal(-1.79769313486232e308 - 1); + } {-Inf} + do_execsql_test func4-2.21 { + SELECT toreal(-1.79769313486232e308); + } {-Inf} + do_execsql_test func4-2.22 { + SELECT toreal(-1.79769313486232e308 + 1); + } {-Inf} + do_execsql_test func4-2.23 { + SELECT toreal(-9223372036854775808 - 1); + } {-9.223372036854776e+18} + do_execsql_test func4-2.24 { + SELECT toreal(-9223372036854775808); + } {-9.223372036854776e+18} + if {$highPrecision(2)} { + do_execsql_test func4-2.25 { + SELECT toreal(-9223372036854775808 + 1); + } {{}} + } + do_execsql_test func4-2.26 { + SELECT toreal(-9223372036854775807 - 1); + } {-9.223372036854776e+18} + if {$highPrecision(2)} { + do_execsql_test func4-2.27 { + SELECT toreal(-9223372036854775807); + } {{}} + do_execsql_test func4-2.28 { + SELECT toreal(-9223372036854775807 + 1); + } {{}} + } + do_execsql_test func4-2.29 { + SELECT toreal(-2147483648 - 1); + } {-2147483649.0} + do_execsql_test func4-2.30 { + SELECT toreal(-2147483648); + } {-2147483648.0} + do_execsql_test func4-2.31 { + SELECT toreal(-2147483648 + 1); + } {-2147483647.0} + do_execsql_test func4-2.32 { + SELECT toreal(2147483647 - 1); + } {2147483646.0} + do_execsql_test func4-2.33 { + SELECT toreal(2147483647); + } {2147483647.0} + do_execsql_test func4-2.34 { + SELECT toreal(2147483647 + 1); + } {2147483648.0} + if {$highPrecision(2)} { + do_execsql_test func4-2.35 { + SELECT toreal(9223372036854775807 - 1); + } {{}} + if {$highPrecision(1)} { + do_execsql_test func4-2.36 { + SELECT toreal(9223372036854775807); + } {{}} + } + } + do_execsql_test func4-2.37 { + SELECT toreal(9223372036854775807 + 1); + } {9.223372036854776e+18} + do_execsql_test func4-2.38 { + SELECT toreal(1.79769313486232e308 - 1); + } {Inf} + do_execsql_test func4-2.39 { + SELECT toreal(1.79769313486232e308); + } {Inf} + do_execsql_test func4-2.40 { + SELECT toreal(1.79769313486232e308 + 1); + } {Inf} + do_execsql_test func4-2.41 { + SELECT toreal(4503599627370496 - 1); + } {4503599627370495.0} + do_execsql_test func4-2.42 { + SELECT toreal(4503599627370496); + } {4503599627370496.0} + do_execsql_test func4-2.43 { + SELECT toreal(4503599627370496 + 1); + } {4503599627370497.0} + do_execsql_test func4-2.44 { + SELECT toreal(9007199254740992 - 1); + } {9007199254740991.0} + do_execsql_test func4-2.45 { + SELECT toreal(9007199254740992); + } {9007199254740992.0} + if {$highPrecision(2)} { + do_execsql_test func4-2.46 { + SELECT toreal(9007199254740992 + 1); + } {{}} + } + do_execsql_test func4-2.47 { + SELECT toreal(9007199254740992 + 2); + } {9007199254740994.0} + do_execsql_test func4-2.48 { + SELECT toreal(tointeger(9223372036854775808) - 1); + } {{}} + if {$highPrecision(1)} { + do_execsql_test func4-2.49 { + SELECT toreal(tointeger(9223372036854775808)); + } {{}} + do_execsql_test func4-2.50 { + SELECT toreal(tointeger(9223372036854775808) + 1); + } {{}} + } + do_execsql_test func4-2.51 { + SELECT toreal(tointeger(18446744073709551616) - 1); + } {{}} + do_execsql_test func4-2.52 { + SELECT toreal(tointeger(18446744073709551616)); + } {{}} + do_execsql_test func4-2.53 { + SELECT toreal(tointeger(18446744073709551616) + 1); + } {{}} +} + +ifcapable check { + do_execsql_test func4-3.1 { + CREATE TABLE t1( + x INTEGER CHECK(tointeger(x) IS NOT NULL) + ); + } {} + do_test func4-3.2 { + catchsql { + INSERT INTO t1 (x) VALUES (NULL); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.3 { + catchsql { + INSERT INTO t1 (x) VALUES (NULL); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.4 { + catchsql { + INSERT INTO t1 (x) VALUES (''); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.5 { + catchsql { + INSERT INTO t1 (x) VALUES ('bad'); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.6 { + catchsql { + INSERT INTO t1 (x) VALUES ('1234bad'); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.7 { + catchsql { + INSERT INTO t1 (x) VALUES ('1234.56bad'); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.8 { + catchsql { + INSERT INTO t1 (x) VALUES (1234); + } + } {0 {}} + do_test func4-3.9 { + catchsql { + INSERT INTO t1 (x) VALUES (1234.56); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.10 { + catchsql { + INSERT INTO t1 (x) VALUES ('1234'); + } + } {0 {}} + do_test func4-3.11 { + catchsql { + INSERT INTO t1 (x) VALUES ('1234.56'); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.12 { + catchsql { + INSERT INTO t1 (x) VALUES (ZEROBLOB(4)); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.13 { + catchsql { + INSERT INTO t1 (x) VALUES (X''); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.14 { + catchsql { + INSERT INTO t1 (x) VALUES (X'1234'); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.15 { + catchsql { + INSERT INTO t1 (x) VALUES (X'12345678'); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.16 { + catchsql { + INSERT INTO t1 (x) VALUES ('1234.00'); + } + } {1 {CHECK constraint failed: t1}} + do_test func4-3.17 { + catchsql { + INSERT INTO t1 (x) VALUES (1234.00); + } + } {0 {}} + do_test func4-3.18 { + catchsql { + INSERT INTO t1 (x) VALUES ('-9223372036854775809'); + } + } {1 {CHECK constraint failed: t1}} + if {$highPrecision(1)} { + do_test func4-3.19 { + catchsql { + INSERT INTO t1 (x) VALUES (9223372036854775808); + } + } {1 {CHECK constraint failed: t1}} + } + do_execsql_test func4-3.20 { + SELECT x FROM t1 ORDER BY x; + } {1234 1234 1234} + + ifcapable floatingpoint { + do_execsql_test func4-4.1 { + CREATE TABLE t2( + x REAL CHECK(toreal(x) IS NOT NULL) + ); + } {} + do_test func4-4.2 { + catchsql { + INSERT INTO t2 (x) VALUES (NULL); + } + } {1 {CHECK constraint failed: t2}} + do_test func4-4.3 { + catchsql { + INSERT INTO t2 (x) VALUES (NULL); + } + } {1 {CHECK constraint failed: t2}} + do_test func4-4.4 { + catchsql { + INSERT INTO t2 (x) VALUES (''); + } + } {1 {CHECK constraint failed: t2}} + do_test func4-4.5 { + catchsql { + INSERT INTO t2 (x) VALUES ('bad'); + } + } {1 {CHECK constraint failed: t2}} + do_test func4-4.6 { + catchsql { + INSERT INTO t2 (x) VALUES ('1234bad'); + } + } {1 {CHECK constraint failed: t2}} + do_test func4-4.7 { + catchsql { + INSERT INTO t2 (x) VALUES ('1234.56bad'); + } + } {1 {CHECK constraint failed: t2}} + do_test func4-4.8 { + catchsql { + INSERT INTO t2 (x) VALUES (1234); + } + } {0 {}} + do_test func4-4.9 { + catchsql { + INSERT INTO t2 (x) VALUES (1234.56); + } + } {0 {}} + do_test func4-4.10 { + catchsql { + INSERT INTO t2 (x) VALUES ('1234'); + } + } {0 {}} + do_test func4-4.11 { + catchsql { + INSERT INTO t2 (x) VALUES ('1234.56'); + } + } {0 {}} + do_test func4-4.12 { + catchsql { + INSERT INTO t2 (x) VALUES (ZEROBLOB(4)); + } + } {1 {CHECK constraint failed: t2}} + do_test func4-4.13 { + catchsql { + INSERT INTO t2 (x) VALUES (X''); + } + } {1 {CHECK constraint failed: t2}} + do_test func4-4.14 { + catchsql { + INSERT INTO t2 (x) VALUES (X'1234'); + } + } {1 {CHECK constraint failed: t2}} + do_test func4-4.15 { + catchsql { + INSERT INTO t2 (x) VALUES (X'12345678'); + } + } {1 {CHECK constraint failed: t2}} + do_execsql_test func4-4.16 { + SELECT x FROM t2 ORDER BY x; + } {1234.0 1234.0 1234.56 1234.56} + } +} + +ifcapable floatingpoint { + do_execsql_test func4-5.1 { + SELECT tointeger(toreal('1234')); + } {1234} + do_execsql_test func4-5.2 { + SELECT tointeger(toreal(-1)); + } {-1} + do_execsql_test func4-5.3 { + SELECT tointeger(toreal(-0)); + } {0} + do_execsql_test func4-5.4 { + SELECT tointeger(toreal(0)); + } {0} + do_execsql_test func4-5.5 { + SELECT tointeger(toreal(1)); + } {1} + do_execsql_test func4-5.6 { + SELECT tointeger(toreal(-9223372036854775808 - 1)); + } {-9223372036854775808} + do_execsql_test func4-5.7 { + SELECT tointeger(toreal(-9223372036854775808)); + } {-9223372036854775808} + if {$highPrecision(2)} { + do_execsql_test func4-5.8 { + SELECT tointeger(toreal(-9223372036854775808 + 1)); + } {{}} + } + do_execsql_test func4-5.9 { + SELECT tointeger(toreal(-2147483648 - 1)); + } {-2147483649} + do_execsql_test func4-5.10 { + SELECT tointeger(toreal(-2147483648)); + } {-2147483648} + do_execsql_test func4-5.11 { + SELECT tointeger(toreal(-2147483648 + 1)); + } {-2147483647} + do_execsql_test func4-5.12 { + SELECT tointeger(toreal(2147483647 - 1)); + } {2147483646} + do_execsql_test func4-5.13 { + SELECT tointeger(toreal(2147483647)); + } {2147483647} + do_execsql_test func4-5.14 { + SELECT tointeger(toreal(2147483647 + 1)); + } {2147483648} + do_execsql_test func4-5.15 { + SELECT tointeger(toreal(9223372036854775807 - 1)); + } {{}} + if {$highPrecision(1)} { + do_execsql_test func4-5.16 { + SELECT tointeger(toreal(9223372036854775807)); + } {{}} + do_execsql_test func4-5.17 { + SELECT tointeger(toreal(9223372036854775807 + 1)); + } {{}} + } + do_execsql_test func4-5.18 { + SELECT tointeger(toreal(4503599627370496 - 1)); + } {4503599627370495} + do_execsql_test func4-5.19 { + SELECT tointeger(toreal(4503599627370496)); + } {4503599627370496} + do_execsql_test func4-5.20 { + SELECT tointeger(toreal(4503599627370496 + 1)); + } {4503599627370497} + do_execsql_test func4-5.21 { + SELECT tointeger(toreal(9007199254740992 - 1)); + } {9007199254740991} + do_execsql_test func4-5.22 { + SELECT tointeger(toreal(9007199254740992)); + } {9007199254740992} + if {$highPrecision(2)} { + do_execsql_test func4-5.23 { + SELECT tointeger(toreal(9007199254740992 + 1)); + } {{}} + } + do_execsql_test func4-5.24 { + SELECT tointeger(toreal(9007199254740992 + 2)); + } {9007199254740994} + if {$highPrecision(1)} { + do_execsql_test func4-5.25 { + SELECT tointeger(toreal(9223372036854775808 - 1)); + } {{}} + do_execsql_test func4-5.26 { + SELECT tointeger(toreal(9223372036854775808)); + } {{}} + do_execsql_test func4-5.27 { + SELECT tointeger(toreal(9223372036854775808 + 1)); + } {{}} + } + do_execsql_test func4-5.28 { + SELECT tointeger(toreal(18446744073709551616 - 1)); + } {{}} + do_execsql_test func4-5.29 { + SELECT tointeger(toreal(18446744073709551616)); + } {{}} + do_execsql_test func4-5.30 { + SELECT tointeger(toreal(18446744073709551616 + 1)); + } {{}} +} + +for {set i 0} {$i < 10} {incr i} { + if {$i == 8} continue + do_execsql_test func4-6.1.$i.1 [subst { + SELECT tointeger(x'[string repeat 01 $i]'); + }] {{}} + ifcapable floatingpoint { + do_execsql_test func4-6.1.$i.2 [subst { + SELECT toreal(x'[string repeat 01 $i]'); + }] {{}} + } +} + +do_execsql_test func4-6.2.1 { + SELECT tointeger(x'0102030405060708'); +} {578437695752307201} +do_execsql_test func4-6.2.2 { + SELECT tointeger(x'0807060504030201'); +} {72623859790382856} + +ifcapable floatingpoint { + do_execsql_test func4-6.3.1 { + SELECT toreal(x'ffefffffffffffff'); + } {-1.7976931348623157e+308} + do_execsql_test func4-6.3.2 { + SELECT toreal(x'8010000000000000'); + } {-2.2250738585072014e-308} + do_execsql_test func4-6.3.3 { + SELECT toreal(x'c000000000000000'); + } {-2.0} + do_execsql_test func4-6.3.4 { + SELECT toreal(x'bff0000000000000'); + } {-1.0} + do_execsql_test func4-6.3.5 { + SELECT toreal(x'8000000000000000'); + } {-0.0} + do_execsql_test func4-6.3.6 { + SELECT toreal(x'0000000000000000'); + } {0.0} + do_execsql_test func4-6.3.7 { + SELECT toreal(x'3ff0000000000000'); + } {1.0} + do_execsql_test func4-6.3.8 { + SELECT toreal(x'4000000000000000'); + } {2.0} + do_execsql_test func4-6.3.9 { + SELECT toreal(x'0010000000000000'); + } {2.2250738585072014e-308} + do_execsql_test func4-6.3.10 { + SELECT toreal(x'7fefffffffffffff'); + } {1.7976931348623157e+308} + do_execsql_test func4-6.3.11 { + SELECT toreal(x'8000000000000001'); + } {-5e-324} + do_execsql_test func4-6.3.12 { + SELECT toreal(x'800fffffffffffff'); + } {-2.225073858507201e-308} + do_execsql_test func4-6.3.13 { + SELECT toreal(x'0000000000000001'); + } {5e-324} + do_execsql_test func4-6.3.14 { + SELECT toreal(x'000fffffffffffff'); + } {2.225073858507201e-308} + do_execsql_test func4-6.3.15 { + SELECT toreal(x'fff0000000000000'); + } {-Inf} + do_execsql_test func4-6.3.16 { + SELECT toreal(x'7ff0000000000000'); + } {Inf} + do_execsql_test func4-6.3.17 { + SELECT toreal(x'fff8000000000000'); + } {{}} + do_execsql_test func4-6.3.18 { + SELECT toreal(x'fff0000000000001'); + } {{}} + do_execsql_test func4-6.3.19 { + SELECT toreal(x'fff7ffffffffffff'); + } {{}} + do_execsql_test func4-6.3.20 { + SELECT toreal(x'7ff0000000000001'); + } {{}} + do_execsql_test func4-6.3.21 { + SELECT toreal(x'7ff7ffffffffffff'); + } {{}} + do_execsql_test func4-6.3.22 { + SELECT toreal(x'fff8000000000001'); + } {{}} + do_execsql_test func4-6.3.23 { + SELECT toreal(x'ffffffffffffffff'); + } {{}} + do_execsql_test func4-6.3.24 { + SELECT toreal(x'7ff8000000000000'); + } {{}} + do_execsql_test func4-6.3.25 { + SELECT toreal(x'7fffffffffffffff'); + } {{}} +} + +set tcl_precision $saved_tcl_precision +unset saved_tcl_precision +finish_test diff --git a/test/func5.test b/test/func5.test new file mode 100644 index 0000000..bfd545b --- /dev/null +++ b/test/func5.test @@ -0,0 +1,63 @@ +# 2013-11-21 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# +# Testing of function factoring and the SQLITE_DETERMINISTIC flag. +# +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Verify that constant string expressions that get factored into initializing +# code are not reused between function parameters and other values in the +# VDBE program, as the function might have changed the encoding. +# +do_execsql_test func5-1.1 { + PRAGMA encoding=UTF16le; + CREATE TABLE t1(x,a,b,c); + INSERT INTO t1 VALUES(1,'ab','cd',1); + INSERT INTO t1 VALUES(2,'gh','ef',5); + INSERT INTO t1 VALUES(3,'pqr','fuzzy',99); + INSERT INTO t1 VALUES(4,'abcdefg','xy',22); + INSERT INTO t1 VALUES(5,'shoe','mayer',2953); + SELECT x FROM t1 WHERE c=instr('abcdefg',b) OR a='abcdefg' ORDER BY +x; +} {2 4} +do_execsql_test func5-1.2 { + SELECT x FROM t1 WHERE a='abcdefg' OR c=instr('abcdefg',b) ORDER BY +x; +} {2 4} + +# Verify that SQLITE_DETERMINISTIC functions get factored out of the +# evaluation loop whereas non-deterministic functions do not. counter1() +# is marked as non-deterministic and so is not factored out of the loop, +# and it really is non-deterministic, returning a different result each +# time. But counter2() is marked as deterministic, so it does get factored +# out of the loop. counter2() has the same implementation as counter1(), +# returning a different result on each invocation, but because it is +# only invoked once outside of the loop, it appears to return the same +# result multiple times. +# +do_execsql_test func5-2.1 { + CREATE TABLE t2(x,y); + INSERT INTO t2 VALUES(1,2),(3,4),(5,6),(7,8); + SELECT x, y FROM t2 WHERE x+5=5+x ORDER BY +x; +} {1 2 3 4 5 6 7 8} +sqlite3_create_function db +do_execsql_test func5-2.2 { + SELECT x, y FROM t2 + WHERE x+counter1('hello')=counter1('hello')+x + ORDER BY +x; +} {} +do_execsql_test func5-2.3 { + SELECT x, y FROM t2 + WHERE x+counter2('hello')=counter2('hello')+x + ORDER BY +x; +} {1 2 3 4 5 6 7 8} + + +finish_test diff --git a/test/fuzz.test b/test/fuzz.test index e1b22ae..0deed3b 100644 --- a/test/fuzz.test +++ b/test/fuzz.test @@ -285,7 +285,7 @@ do_test fuzz-1.18 { ) )) } -} {0 -4294967298} +} {0 {{}}} # At one point the following INSERT statement caused an assert() to fail. # diff --git a/test/fuzz3.test b/test/fuzz3.test index d0efc52..2b21404 100644 --- a/test/fuzz3.test +++ b/test/fuzz3.test @@ -18,6 +18,9 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +# These tests deal with corrupt database files +# +database_may_be_corrupt expr srand(123) diff --git a/test/fuzzer1.test b/test/fuzzer1.test index 473d0e1..4ee5730 100644 --- a/test/fuzzer1.test +++ b/test/fuzzer1.test @@ -1728,36 +1728,41 @@ do_execsql_test 8.1 { do_execsql_test 8.2.1 { SELECT cFrom, cTo, word FROM x3_rules CROSS JOIN x3 - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo; } {a x x a y y a z z} do_execsql_test 8.2.2 { SELECT cFrom, cTo, word FROM x3 CROSS JOIN x3_rules - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo DESC } {a z z a y y a x x} do_execsql_test 8.2.3 { SELECT cFrom, cTo, word FROM x3_rules, x3 - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo DESC; } {a z z a y y a x x} do_execsql_test 8.2.4 { SELECT cFrom, cTo, word FROM x3, x3_rules - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo DESC; } {a z z a y y a x x} do_execsql_test 8.2.5 { CREATE INDEX i1 ON x3_rules(cost); SELECT cFrom, cTo, word FROM x3_rules, x3 - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo DESC; } {a z z a y y a x x} do_execsql_test 8.2.5 { - SELECT word FROM x3_rules, x3 WHERE word MATCH x3_rules.cFrom AND ruleset=2; + SELECT word FROM x3_rules, x3 WHERE word MATCH x3_rules.cFrom AND ruleset=2 } {a z y x a z y x a z y x} do_execsql_test 8.2.6 { diff --git a/test/genesis.tcl b/test/genesis.tcl new file mode 100644 index 0000000..4ba4c8e --- /dev/null +++ b/test/genesis.tcl @@ -0,0 +1,1560 @@ +# 2010 February 02 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements a TCL function that fills an FTS table with +# lots of content useful for testing. This routine is broken out into +# a separate file to facilitate its use by multiple test scripts. +# + +# The fts_kjv_genesis routine is already loaded. This script is a no-op. +if {[lsearch [info procs] fts_kjv_genesis]>=0} return + +# This procedure fills an existing FTS3/FTS4 table with many entries. +# The table needs to have a single column (other than docid) named "words". +# +proc fts_kjv_genesis {} { +db eval { +BEGIN TRANSACTION; +INSERT INTO t1(docid,words) VALUES(1001001,'In the beginning God created the heaven and the earth.'); +INSERT INTO t1(docid,words) VALUES(1001002,'And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.'); +INSERT INTO t1(docid,words) VALUES(1001003,'And God said, Let there be light: and there was light.'); +INSERT INTO t1(docid,words) VALUES(1001004,'And God saw the light, that it was good: and God divided the light from the darkness.'); +INSERT INTO t1(docid,words) VALUES(1001005,'And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day.'); +INSERT INTO t1(docid,words) VALUES(1001006,'And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters.'); +INSERT INTO t1(docid,words) VALUES(1001007,'And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so.'); +INSERT INTO t1(docid,words) VALUES(1001008,'And God called the firmament Heaven. And the evening and the morning were the second day.'); +INSERT INTO t1(docid,words) VALUES(1001009,'And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so.'); +INSERT INTO t1(docid,words) VALUES(1001010,'And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good.'); +INSERT INTO t1(docid,words) VALUES(1001011,'And God said, Let the earth bring forth grass, the herb yielding seed, and the fruit tree yielding fruit after his kind, whose seed is in itself, upon the earth: and it was so.'); +INSERT INTO t1(docid,words) VALUES(1001012,'And the earth brought forth grass, and herb yielding seed after his kind, and the tree yielding fruit, whose seed was in itself, after his kind: and God saw that it was good.'); +INSERT INTO t1(docid,words) VALUES(1001013,'And the evening and the morning were the third day.'); +INSERT INTO t1(docid,words) VALUES(1001014,'And God said, Let there be lights in the firmament of the heaven to divide the day from the night; and let them be for signs, and for seasons, and for days, and years:'); +INSERT INTO t1(docid,words) VALUES(1001015,'And let them be for lights in the firmament of the heaven to give light upon the earth: and it was so.'); +INSERT INTO t1(docid,words) VALUES(1001016,'And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: he made the stars also.'); +INSERT INTO t1(docid,words) VALUES(1001017,'And God set them in the firmament of the heaven to give light upon the earth,'); +INSERT INTO t1(docid,words) VALUES(1001018,'And to rule over the day and over the night, and to divide the light from the darkness: and God saw that it was good.'); +INSERT INTO t1(docid,words) VALUES(1001019,'And the evening and the morning were the fourth day.'); +INSERT INTO t1(docid,words) VALUES(1001020,'And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl that may fly above the earth in the open firmament of heaven.'); +INSERT INTO t1(docid,words) VALUES(1001021,'And God created great whales, and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that it was good.'); +INSERT INTO t1(docid,words) VALUES(1001022,'And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth.'); +INSERT INTO t1(docid,words) VALUES(1001023,'And the evening and the morning were the fifth day.'); +INSERT INTO t1(docid,words) VALUES(1001024,'And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so.'); +INSERT INTO t1(docid,words) VALUES(1001025,'And God made the beast of the earth after his kind, and cattle after their kind, and every thing that creepeth upon the earth after his kind: and God saw that it was good.'); +INSERT INTO t1(docid,words) VALUES(1001026,'And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth.'); +INSERT INTO t1(docid,words) VALUES(1001027,'So God created man in his own image, in the image of God created he him; male and female created he them.'); +INSERT INTO t1(docid,words) VALUES(1001028,'And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth.'); +INSERT INTO t1(docid,words) VALUES(1001029,'And God said, Behold, I have given you every herb bearing seed, which is upon the face of all the earth, and every tree, in the which is the fruit of a tree yielding seed; to you it shall be for meat.'); +INSERT INTO t1(docid,words) VALUES(1001030,'And to every beast of the earth, and to every fowl of the air, and to every thing that creepeth upon the earth, wherein there is life, I have given every green herb for meat: and it was so.'); +INSERT INTO t1(docid,words) VALUES(1001031,'And God saw every thing that he had made, and, behold, it was very good. And the evening and the morning were the sixth day.'); +INSERT INTO t1(docid,words) VALUES(1002001,'Thus the heavens and the earth were finished, and all the host of them.'); +INSERT INTO t1(docid,words) VALUES(1002002,'And on the seventh day God ended his work which he had made; and he rested on the seventh day from all his work which he had made.'); +INSERT INTO t1(docid,words) VALUES(1002003,'And God blessed the seventh day, and sanctified it: because that in it he had rested from all his work which God created and made.'); +INSERT INTO t1(docid,words) VALUES(1002004,'These are the generations of the heavens and of the earth when they were created, in the day that the LORD God made the earth and the heavens,'); +INSERT INTO t1(docid,words) VALUES(1002005,'And every plant of the field before it was in the earth, and every herb of the field before it grew: for the LORD God had not caused it to rain upon the earth, and there was not a man to till the ground.'); +INSERT INTO t1(docid,words) VALUES(1002006,'But there went up a mist from the earth, and watered the whole face of the ground.'); +INSERT INTO t1(docid,words) VALUES(1002007,'And the LORD God formed man of the dust of the ground, and breathed into his nostrils the breath of life; and man became a living soul.'); +INSERT INTO t1(docid,words) VALUES(1002008,'And the LORD God planted a garden eastward in Eden; and there he put the man whom he had formed.'); +INSERT INTO t1(docid,words) VALUES(1002009,'And out of the ground made the LORD God to grow every tree that is pleasant to the sight, and good for food; the tree of life also in the midst of the garden, and the tree of knowledge of good and evil.'); +INSERT INTO t1(docid,words) VALUES(1002010,'And a river went out of Eden to water the garden; and from thence it was parted, and became into four heads.'); +INSERT INTO t1(docid,words) VALUES(1002011,'The name of the first is Pison: that is it which compasseth the whole land of Havilah, where there is gold;'); +INSERT INTO t1(docid,words) VALUES(1002012,'And the gold of that land is good: there is bdellium and the onyx stone.'); +INSERT INTO t1(docid,words) VALUES(1002013,'And the name of the second river is Gihon: the same is it that compasseth the whole land of Ethiopia.'); +INSERT INTO t1(docid,words) VALUES(1002014,'And the name of the third river is Hiddekel: that is it which goeth toward the east of Assyria. And the fourth river is Euphrates.'); +INSERT INTO t1(docid,words) VALUES(1002015,'And the LORD God took the man, and put him into the garden of Eden to dress it and to keep it.'); +INSERT INTO t1(docid,words) VALUES(1002016,'And the LORD God commanded the man, saying, Of every tree of the garden thou mayest freely eat:'); +INSERT INTO t1(docid,words) VALUES(1002017,'But of the tree of the knowledge of good and evil, thou shalt not eat of it: for in the day that thou eatest thereof thou shalt surely die.'); +INSERT INTO t1(docid,words) VALUES(1002018,'And the LORD God said, It is not good that the man should be alone; I will make him an help meet for him.'); +INSERT INTO t1(docid,words) VALUES(1002019,'And out of the ground the LORD God formed every beast of the field, and every fowl of the air; and brought them unto Adam to see what he would call them: and whatsoever Adam called every living creature, that was the name thereof.'); +INSERT INTO t1(docid,words) VALUES(1002020,'And Adam gave names to all cattle, and to the fowl of the air, and to every beast of the field; but for Adam there was not found an help meet for him.'); +INSERT INTO t1(docid,words) VALUES(1002021,'And the LORD God caused a deep sleep to fall upon Adam, and he slept: and he took one of his ribs, and closed up the flesh instead thereof;'); +INSERT INTO t1(docid,words) VALUES(1002022,'And the rib, which the LORD God had taken from man, made he a woman, and brought her unto the man.'); +INSERT INTO t1(docid,words) VALUES(1002023,'And Adam said, This is now bone of my bones, and flesh of my flesh: she shall be called Woman, because she was taken out of Man.'); +INSERT INTO t1(docid,words) VALUES(1002024,'Therefore shall a man leave his father and his mother, and shall cleave unto his wife: and they shall be one flesh.'); +INSERT INTO t1(docid,words) VALUES(1002025,'And they were both naked, the man and his wife, and were not ashamed.'); +INSERT INTO t1(docid,words) VALUES(1003001,'Now the serpent was more subtil than any beast of the field which the LORD God had made. And he said unto the woman, Yea, hath God said, Ye shall not eat of every tree of the garden?'); +INSERT INTO t1(docid,words) VALUES(1003002,'And the woman said unto the serpent, We may eat of the fruit of the trees of the garden:'); +INSERT INTO t1(docid,words) VALUES(1003003,'But of the fruit of the tree which is in the midst of the garden, God hath said, Ye shall not eat of it, neither shall ye touch it, lest ye die.'); +INSERT INTO t1(docid,words) VALUES(1003004,'And the serpent said unto the woman, Ye shall not surely die:'); +INSERT INTO t1(docid,words) VALUES(1003005,'For God doth know that in the day ye eat thereof, then your eyes shall be opened, and ye shall be as gods, knowing good and evil.'); +INSERT INTO t1(docid,words) VALUES(1003006,'And when the woman saw that the tree was good for food, and that it was pleasant to the eyes, and a tree to be desired to make one wise, she took of the fruit thereof, and did eat, and gave also unto her husband with her; and he did eat.'); +INSERT INTO t1(docid,words) VALUES(1003007,'And the eyes of them both were opened, and they knew that they were naked; and they sewed fig leaves together, and made themselves aprons.'); +INSERT INTO t1(docid,words) VALUES(1003008,'And they heard the voice of the LORD God walking in the garden in the cool of the day: and Adam and his wife hid themselves from the presence of the LORD God amongst the trees of the garden.'); +INSERT INTO t1(docid,words) VALUES(1003009,'And the LORD God called unto Adam, and said unto him, Where art thou?'); +INSERT INTO t1(docid,words) VALUES(1003010,'And he said, I heard thy voice in the garden, and I was afraid, because I was naked; and I hid myself.'); +INSERT INTO t1(docid,words) VALUES(1003011,'And he said, Who told thee that thou wast naked? Hast thou eaten of the tree, whereof I commanded thee that thou shouldest not eat?'); +INSERT INTO t1(docid,words) VALUES(1003012,'And the man said, The woman whom thou gavest to be with me, she gave me of the tree, and I did eat.'); +INSERT INTO t1(docid,words) VALUES(1003013,'And the LORD God said unto the woman, What is this that thou hast done? And the woman said, The serpent beguiled me, and I did eat.'); +INSERT INTO t1(docid,words) VALUES(1003014,'And the LORD God said unto the serpent, Because thou hast done this, thou art cursed above all cattle, and above every beast of the field; upon thy belly shalt thou go, and dust shalt thou eat all the days of thy life:'); +INSERT INTO t1(docid,words) VALUES(1003015,'And I will put enmity between thee and the woman, and between thy seed and her seed; it shall bruise thy head, and thou shalt bruise his heel.'); +INSERT INTO t1(docid,words) VALUES(1003016,'Unto the woman he said, I will greatly multiply thy sorrow and thy conception; in sorrow thou shalt bring forth children; and thy desire shall be to thy husband, and he shall rule over thee.'); +INSERT INTO t1(docid,words) VALUES(1003017,'And unto Adam he said, Because thou hast hearkened unto the voice of thy wife, and hast eaten of the tree, of which I commanded thee, saying, Thou shalt not eat of it: cursed is the ground for thy sake; in sorrow shalt thou eat of it all the days of thy life;'); +INSERT INTO t1(docid,words) VALUES(1003018,'Thorns also and thistles shall it bring forth to thee; and thou shalt eat the herb of the field;'); +INSERT INTO t1(docid,words) VALUES(1003019,'In the sweat of thy face shalt thou eat bread, till thou return unto the ground; for out of it wast thou taken: for dust thou art, and unto dust shalt thou return.'); +INSERT INTO t1(docid,words) VALUES(1003020,'And Adam called his wife''s name Eve; because she was the mother of all living.'); +INSERT INTO t1(docid,words) VALUES(1003021,'Unto Adam also and to his wife did the LORD God make coats of skins, and clothed them.'); +INSERT INTO t1(docid,words) VALUES(1003022,'And the LORD God said, Behold, the man is become as one of us, to know good and evil: and now, lest he put forth his hand, and take also of the tree of life, and eat, and live for ever:'); +INSERT INTO t1(docid,words) VALUES(1003023,'Therefore the LORD God sent him forth from the garden of Eden, to till the ground from whence he was taken.'); +INSERT INTO t1(docid,words) VALUES(1003024,'So he drove out the man; and he placed at the east of the garden of Eden Cherubims, and a flaming sword which turned every way, to keep the way of the tree of life.'); +INSERT INTO t1(docid,words) VALUES(1004001,'And Adam knew Eve his wife; and she conceived, and bare Cain, and said, I have gotten a man from the LORD.'); +INSERT INTO t1(docid,words) VALUES(1004002,'And she again bare his brother Abel. And Abel was a keeper of sheep, but Cain was a tiller of the ground.'); +INSERT INTO t1(docid,words) VALUES(1004003,'And in process of time it came to pass, that Cain brought of the fruit of the ground an offering unto the LORD.'); +INSERT INTO t1(docid,words) VALUES(1004004,'And Abel, he also brought of the firstlings of his flock and of the fat thereof. And the LORD had respect unto Abel and to his offering:'); +INSERT INTO t1(docid,words) VALUES(1004005,'But unto Cain and to his offering he had not respect. And Cain was very wroth, and his countenance fell.'); +INSERT INTO t1(docid,words) VALUES(1004006,'And the LORD said unto Cain, Why art thou wroth? and why is thy countenance fallen?'); +INSERT INTO t1(docid,words) VALUES(1004007,'If thou doest well, shalt thou not be accepted? and if thou doest not well, sin lieth at the door. And unto thee shall be his desire, and thou shalt rule over him.'); +INSERT INTO t1(docid,words) VALUES(1004008,'And Cain talked with Abel his brother: and it came to pass, when they were in the field, that Cain rose up against Abel his brother, and slew him.'); +INSERT INTO t1(docid,words) VALUES(1004009,'And the LORD said unto Cain, Where is Abel thy brother? And he said, I know not: Am I my brother''s keeper?'); +INSERT INTO t1(docid,words) VALUES(1004010,'And he said, What hast thou done? the voice of thy brother''s blood crieth unto me from the ground.'); +INSERT INTO t1(docid,words) VALUES(1004011,'And now art thou cursed from the earth, which hath opened her mouth to receive thy brother''s blood from thy hand;'); +INSERT INTO t1(docid,words) VALUES(1004012,'When thou tillest the ground, it shall not henceforth yield unto thee her strength; a fugitive and a vagabond shalt thou be in the earth.'); +INSERT INTO t1(docid,words) VALUES(1004013,'And Cain said unto the LORD, My punishment is greater than I can bear.'); +INSERT INTO t1(docid,words) VALUES(1004014,'Behold, thou hast driven me out this day from the face of the earth; and from thy face shall I be hid; and I shall be a fugitive and a vagabond in the earth; and it shall come to pass, that every one that findeth me shall slay me.'); +INSERT INTO t1(docid,words) VALUES(1004015,'And the LORD said unto him, Therefore whosoever slayeth Cain, vengeance shall be taken on him sevenfold. And the LORD set a mark upon Cain, lest any finding him should kill him.'); +INSERT INTO t1(docid,words) VALUES(1004016,'And Cain went out from the presence of the LORD, and dwelt in the land of Nod, on the east of Eden.'); +INSERT INTO t1(docid,words) VALUES(1004017,'And Cain knew his wife; and she conceived, and bare Enoch: and he builded a city, and called the name of the city, after the name of his son, Enoch.'); +INSERT INTO t1(docid,words) VALUES(1004018,'And unto Enoch was born Irad: and Irad begat Mehujael: and Mehujael begat Methusael: and Methusael begat Lamech.'); +INSERT INTO t1(docid,words) VALUES(1004019,'And Lamech took unto him two wives: the name of the one was Adah, and the name of the other Zillah.'); +INSERT INTO t1(docid,words) VALUES(1004020,'And Adah bare Jabal: he was the father of such as dwell in tents, and of such as have cattle.'); +INSERT INTO t1(docid,words) VALUES(1004021,'And his brother''s name was Jubal: he was the father of all such as handle the harp and organ.'); +INSERT INTO t1(docid,words) VALUES(1004022,'And Zillah, she also bare Tubalcain, an instructer of every artificer in brass and iron: and the sister of Tubalcain was Naamah.'); +INSERT INTO t1(docid,words) VALUES(1004023,'And Lamech said unto his wives, Adah and Zillah, Hear my voice; ye wives of Lamech, hearken unto my speech: for I have slain a man to my wounding, and a young man to my hurt.'); +INSERT INTO t1(docid,words) VALUES(1004024,'If Cain shall be avenged sevenfold, truly Lamech seventy and sevenfold.'); +INSERT INTO t1(docid,words) VALUES(1004025,'And Adam knew his wife again; and she bare a son, and called his name Seth: For God, said she, hath appointed me another seed instead of Abel, whom Cain slew.'); +INSERT INTO t1(docid,words) VALUES(1004026,'And to Seth, to him also there was born a son; and he called his name Enos: then began men to call upon the name of the LORD.'); +INSERT INTO t1(docid,words) VALUES(1005001,'This is the book of the generations of Adam. In the day that God created man, in the likeness of God made he him;'); +INSERT INTO t1(docid,words) VALUES(1005002,'Male and female created he them; and blessed them, and called their name Adam, in the day when they were created.'); +INSERT INTO t1(docid,words) VALUES(1005003,'And Adam lived an hundred and thirty years, and begat a son in his own likeness, and after his image; and called his name Seth:'); +INSERT INTO t1(docid,words) VALUES(1005004,'And the days of Adam after he had begotten Seth were eight hundred years: and he begat sons and daughters:'); +INSERT INTO t1(docid,words) VALUES(1005005,'And all the days that Adam lived were nine hundred and thirty years: and he died.'); +INSERT INTO t1(docid,words) VALUES(1005006,'And Seth lived an hundred and five years, and begat Enos:'); +INSERT INTO t1(docid,words) VALUES(1005007,'And Seth lived after he begat Enos eight hundred and seven years, and begat sons and daughters:'); +INSERT INTO t1(docid,words) VALUES(1005008,'And all the days of Seth were nine hundred and twelve years: and he died.'); +INSERT INTO t1(docid,words) VALUES(1005009,'And Enos lived ninety years, and begat Cainan:'); +INSERT INTO t1(docid,words) VALUES(1005010,'And Enos lived after he begat Cainan eight hundred and fifteen years, and begat sons and daughters:'); +INSERT INTO t1(docid,words) VALUES(1005011,'And all the days of Enos were nine hundred and five years: and he died.'); +INSERT INTO t1(docid,words) VALUES(1005012,'And Cainan lived seventy years and begat Mahalaleel:'); +INSERT INTO t1(docid,words) VALUES(1005013,'And Cainan lived after he begat Mahalaleel eight hundred and forty years, and begat sons and daughters:'); +INSERT INTO t1(docid,words) VALUES(1005014,'And all the days of Cainan were nine hundred and ten years: and he died.'); +INSERT INTO t1(docid,words) VALUES(1005015,'And Mahalaleel lived sixty and five years, and begat Jared:'); +INSERT INTO t1(docid,words) VALUES(1005016,'And Mahalaleel lived after he begat Jared eight hundred and thirty years, and begat sons and daughters:'); +INSERT INTO t1(docid,words) VALUES(1005017,'And all the days of Mahalaleel were eight hundred ninety and five years: and he died.'); +INSERT INTO t1(docid,words) VALUES(1005018,'And Jared lived an hundred sixty and two years, and he begat Enoch:'); +INSERT INTO t1(docid,words) VALUES(1005019,'And Jared lived after he begat Enoch eight hundred years, and begat sons and daughters:'); +INSERT INTO t1(docid,words) VALUES(1005020,'And all the days of Jared were nine hundred sixty and two years: and he died.'); +INSERT INTO t1(docid,words) VALUES(1005021,'And Enoch lived sixty and five years, and begat Methuselah:'); +INSERT INTO t1(docid,words) VALUES(1005022,'And Enoch walked with God after he begat Methuselah three hundred years, and begat sons and daughters:'); +INSERT INTO t1(docid,words) VALUES(1005023,'And all the days of Enoch were three hundred sixty and five years:'); +INSERT INTO t1(docid,words) VALUES(1005024,'And Enoch walked with God: and he was not; for God took him.'); +INSERT INTO t1(docid,words) VALUES(1005025,'And Methuselah lived an hundred eighty and seven years, and begat Lamech.'); +INSERT INTO t1(docid,words) VALUES(1005026,'And Methuselah lived after he begat Lamech seven hundred eighty and two years, and begat sons and daughters:'); +INSERT INTO t1(docid,words) VALUES(1005027,'And all the days of Methuselah were nine hundred sixty and nine years: and he died.'); +INSERT INTO t1(docid,words) VALUES(1005028,'And Lamech lived an hundred eighty and two years, and begat a son:'); +INSERT INTO t1(docid,words) VALUES(1005029,'And he called his name Noah, saying, This same shall comfort us concerning our work and toil of our hands, because of the ground which the LORD hath cursed.'); +INSERT INTO t1(docid,words) VALUES(1005030,'And Lamech lived after he begat Noah five hundred ninety and five years, and begat sons and daughters:'); +INSERT INTO t1(docid,words) VALUES(1005031,'And all the days of Lamech were seven hundred seventy and seven years: and he died.'); +INSERT INTO t1(docid,words) VALUES(1005032,'And Noah was five hundred years old: and Noah begat Shem, Ham, and Japheth.'); +INSERT INTO t1(docid,words) VALUES(1006001,'And it came to pass, when men began to multiply on the face of the earth, and daughters were born unto them,'); +INSERT INTO t1(docid,words) VALUES(1006002,'That the sons of God saw the daughters of men that they were fair; and they took them wives of all which they chose.'); +INSERT INTO t1(docid,words) VALUES(1006003,'And the LORD said, My spirit shall not always strive with man, for that he also is flesh: yet his days shall be an hundred and twenty years.'); +INSERT INTO t1(docid,words) VALUES(1006004,'There were giants in the earth in those days; and also after that, when the sons of God came in unto the daughters of men, and they bare children to them, the same became mighty men which were of old, men of renown.'); +INSERT INTO t1(docid,words) VALUES(1006005,'And God saw that the wickedness of man was great in the earth, and that every imagination of the thoughts of his heart was only evil continually.'); +INSERT INTO t1(docid,words) VALUES(1006006,'And it repented the LORD that he had made man on the earth, and it grieved him at his heart.'); +INSERT INTO t1(docid,words) VALUES(1006007,'And the LORD said, I will destroy man whom I have created from the face of the earth; both man, and beast, and the creeping thing, and the fowls of the air; for it repenteth me that I have made them.'); +INSERT INTO t1(docid,words) VALUES(1006008,'But Noah found grace in the eyes of the LORD.'); +INSERT INTO t1(docid,words) VALUES(1006009,'These are the generations of Noah: Noah was a just man and perfect in his generations, and Noah walked with God.'); +INSERT INTO t1(docid,words) VALUES(1006010,'And Noah begat three sons, Shem, Ham, and Japheth.'); +INSERT INTO t1(docid,words) VALUES(1006011,'The earth also was corrupt before God, and the earth was filled with violence.'); +INSERT INTO t1(docid,words) VALUES(1006012,'And God looked upon the earth, and, behold, it was corrupt; for all flesh had corrupted his way upon the earth.'); +INSERT INTO t1(docid,words) VALUES(1006013,'And God said unto Noah, The end of all flesh is come before me; for the earth is filled with violence through them; and, behold, I will destroy them with the earth.'); +INSERT INTO t1(docid,words) VALUES(1006014,'Make thee an ark of gopher wood; rooms shalt thou make in the ark, and shalt pitch it within and without with pitch.'); +INSERT INTO t1(docid,words) VALUES(1006015,'And this is the fashion which thou shalt make it of: The length of the ark shall be three hundred cubits, the breadth of it fifty cubits, and the height of it thirty cubits.'); +INSERT INTO t1(docid,words) VALUES(1006016,'A window shalt thou make to the ark, and in a cubit shalt thou finish it above; and the door of the ark shalt thou set in the side thereof; with lower, second, and third stories shalt thou make it.'); +INSERT INTO t1(docid,words) VALUES(1006017,'And, behold, I, even I, do bring a flood of waters upon the earth, to destroy all flesh, wherein is the breath of life, from under heaven; and every thing that is in the earth shall die.'); +INSERT INTO t1(docid,words) VALUES(1006018,'But with thee will I establish my covenant; and thou shalt come into the ark, thou, and thy sons, and thy wife, and thy sons'' wives with thee.'); +INSERT INTO t1(docid,words) VALUES(1006019,'And of every living thing of all flesh, two of every sort shalt thou bring into the ark, to keep them alive with thee; they shall be male and female.'); +INSERT INTO t1(docid,words) VALUES(1006020,'Of fowls after their kind, and of cattle after their kind, of every creeping thing of the earth after his kind, two of every sort shall come unto thee, to keep them alive.'); +INSERT INTO t1(docid,words) VALUES(1006021,'And take thou unto thee of all food that is eaten, and thou shalt gather it to thee; and it shall be for food for thee, and for them.'); +INSERT INTO t1(docid,words) VALUES(1006022,'Thus did Noah; according to all that God commanded him, so did he.'); +INSERT INTO t1(docid,words) VALUES(1007001,'And the LORD said unto Noah, Come thou and all thy house into the ark; for thee have I seen righteous before me in this generation.'); +INSERT INTO t1(docid,words) VALUES(1007002,'Of every clean beast thou shalt take to thee by sevens, the male and his female: and of beasts that are not clean by two, the male and his female.'); +INSERT INTO t1(docid,words) VALUES(1007003,'Of fowls also of the air by sevens, the male and the female; to keep seed alive upon the face of all the earth.'); +INSERT INTO t1(docid,words) VALUES(1007004,'For yet seven days, and I will cause it to rain upon the earth forty days and forty nights; and every living substance that I have made will I destroy from off the face of the earth.'); +INSERT INTO t1(docid,words) VALUES(1007005,'And Noah did according unto all that the LORD commanded him.'); +INSERT INTO t1(docid,words) VALUES(1007006,'And Noah was six hundred years old when the flood of waters was upon the earth.'); +INSERT INTO t1(docid,words) VALUES(1007007,'And Noah went in, and his sons, and his wife, and his sons'' wives with him, into the ark, because of the waters of the flood.'); +INSERT INTO t1(docid,words) VALUES(1007008,'Of clean beasts, and of beasts that are not clean, and of fowls, and of every thing that creepeth upon the earth,'); +INSERT INTO t1(docid,words) VALUES(1007009,'There went in two and two unto Noah into the ark, the male and the female, as God had commanded Noah.'); +INSERT INTO t1(docid,words) VALUES(1007010,'And it came to pass after seven days, that the waters of the flood were upon the earth.'); +INSERT INTO t1(docid,words) VALUES(1007011,'In the six hundredth year of Noah''s life, in the second month, the seventeenth day of the month, the same day were all the fountains of the great deep broken up, and the windows of heaven were opened.'); +INSERT INTO t1(docid,words) VALUES(1007012,'And the rain was upon the earth forty days and forty nights.'); +INSERT INTO t1(docid,words) VALUES(1007013,'In the selfsame day entered Noah, and Shem, and Ham, and Japheth, the sons of Noah, and Noah''s wife, and the three wives of his sons with them, into the ark;'); +INSERT INTO t1(docid,words) VALUES(1007014,'They, and every beast after his kind, and all the cattle after their kind, and every creeping thing that creepeth upon the earth after his kind, and every fowl after his kind, every bird of every sort.'); +INSERT INTO t1(docid,words) VALUES(1007015,'And they went in unto Noah into the ark, two and two of all flesh, wherein is the breath of life.'); +INSERT INTO t1(docid,words) VALUES(1007016,'And they that went in, went in male and female of all flesh, as God had commanded him: and the LORD shut him in.'); +INSERT INTO t1(docid,words) VALUES(1007017,'And the flood was forty days upon the earth; and the waters increased, and bare up the ark, and it was lift up above the earth.'); +INSERT INTO t1(docid,words) VALUES(1007018,'And the waters prevailed, and were increased greatly upon the earth; and the ark went upon the face of the waters.'); +INSERT INTO t1(docid,words) VALUES(1007019,'And the waters prevailed exceedingly upon the earth; and all the high hills, that were under the whole heaven, were covered.'); +INSERT INTO t1(docid,words) VALUES(1007020,'Fifteen cubits upward did the waters prevail; and the mountains were covered.'); +INSERT INTO t1(docid,words) VALUES(1007021,'And all flesh died that moved upon the earth, both of fowl, and of cattle, and of beast, and of every creeping thing that creepeth upon the earth, and every man:'); +INSERT INTO t1(docid,words) VALUES(1007022,'All in whose nostrils was the breath of life, of all that was in the dry land, died.'); +INSERT INTO t1(docid,words) VALUES(1007023,'And every living substance was destroyed which was upon the face of the ground, both man, and cattle, and the creeping things, and the fowl of the heaven; and they were destroyed from the earth: and Noah only remained alive, and they that were with him in the ark.'); +INSERT INTO t1(docid,words) VALUES(1007024,'And the waters prevailed upon the earth an hundred and fifty days.'); +INSERT INTO t1(docid,words) VALUES(1008001,'And God remembered Noah, and every living thing, and all the cattle that was with him in the ark: and God made a wind to pass over the earth, and the waters asswaged;'); +INSERT INTO t1(docid,words) VALUES(1008002,'The fountains also of the deep and the windows of heaven were stopped, and the rain from heaven was restrained;'); +INSERT INTO t1(docid,words) VALUES(1008003,'And the waters returned from off the earth continually: and after the end of the hundred and fifty days the waters were abated.'); +INSERT INTO t1(docid,words) VALUES(1008004,'And the ark rested in the seventh month, on the seventeenth day of the month, upon the mountains of Ararat.'); +INSERT INTO t1(docid,words) VALUES(1008005,'And the waters decreased continually until the tenth month: in the tenth month, on the first day of the month, were the tops of the mountains seen.'); +INSERT INTO t1(docid,words) VALUES(1008006,'And it came to pass at the end of forty days, that Noah opened the window of the ark which he had made:'); +INSERT INTO t1(docid,words) VALUES(1008007,'And he sent forth a raven, which went forth to and fro, until the waters were dried up from off the earth.'); +INSERT INTO t1(docid,words) VALUES(1008008,'Also he sent forth a dove from him, to see if the waters were abated from off the face of the ground;'); +INSERT INTO t1(docid,words) VALUES(1008009,'But the dove found no rest for the sole of her foot, and she returned unto him into the ark, for the waters were on the face of the whole earth: then he put forth his hand, and took her, and pulled her in unto him into the ark.'); +INSERT INTO t1(docid,words) VALUES(1008010,'And he stayed yet other seven days; and again he sent forth the dove out of the ark;'); +INSERT INTO t1(docid,words) VALUES(1008011,'And the dove came in to him in the evening; and, lo, in her mouth was an olive leaf pluckt off: so Noah knew that the waters were abated from off the earth.'); +INSERT INTO t1(docid,words) VALUES(1008012,'And he stayed yet other seven days; and sent forth the dove; which returned not again unto him any more.'); +INSERT INTO t1(docid,words) VALUES(1008013,'And it came to pass in the six hundredth and first year, in the first month, the first day of the month, the waters were dried up from off the earth: and Noah removed the covering of the ark, and looked, and, behold, the face of the ground was dry.'); +INSERT INTO t1(docid,words) VALUES(1008014,'And in the second month, on the seven and twentieth day of the month, was the earth dried.'); +INSERT INTO t1(docid,words) VALUES(1008015,'And God spake unto Noah, saying,'); +INSERT INTO t1(docid,words) VALUES(1008016,'Go forth of the ark, thou, and thy wife, and thy sons, and thy sons'' wives with thee.'); +INSERT INTO t1(docid,words) VALUES(1008017,'Bring forth with thee every living thing that is with thee, of all flesh, both of fowl, and of cattle, and of every creeping thing that creepeth upon the earth; that they may breed abundantly in the earth, and be fruitful, and multiply upon the earth.'); +INSERT INTO t1(docid,words) VALUES(1008018,'And Noah went forth, and his sons, and his wife, and his sons'' wives with him:'); +INSERT INTO t1(docid,words) VALUES(1008019,'Every beast, every creeping thing, and every fowl, and whatsoever creepeth upon the earth, after their kinds, went forth out of the ark.'); +INSERT INTO t1(docid,words) VALUES(1008020,'And Noah builded an altar unto the LORD; and took of every clean beast, and of every clean fowl, and offered burnt offerings on the altar.'); +INSERT INTO t1(docid,words) VALUES(1008021,'And the LORD smelled a sweet savour; and the LORD said in his heart, I will not again curse the ground any more for man''s sake; for the imagination of man''s heart is evil from his youth; neither will I again smite any more every thing living, as I have done.'); +INSERT INTO t1(docid,words) VALUES(1008022,'While the earth remaineth, seedtime and harvest, and cold and heat, and summer and winter, and day and night shall not cease.'); +INSERT INTO t1(docid,words) VALUES(1009001,'And God blessed Noah and his sons, and said unto them, Be fruitful, and multiply, and replenish the earth.'); +INSERT INTO t1(docid,words) VALUES(1009002,'And the fear of you and the dread of you shall be upon every beast of the earth, and upon every fowl of the air, upon all that moveth upon the earth, and upon all the fishes of the sea; into your hand are they delivered.'); +INSERT INTO t1(docid,words) VALUES(1009003,'Every moving thing that liveth shall be meat for you; even as the green herb have I given you all things.'); +INSERT INTO t1(docid,words) VALUES(1009004,'But flesh with the life thereof, which is the blood thereof, shall ye not eat.'); +INSERT INTO t1(docid,words) VALUES(1009005,'And surely your blood of your lives will I require; at the hand of every beast will I require it, and at the hand of man; at the hand of every man''s brother will I require the life of man.'); +INSERT INTO t1(docid,words) VALUES(1009006,'Whoso sheddeth man''s blood, by man shall his blood be shed: for in the image of God made he man.'); +INSERT INTO t1(docid,words) VALUES(1009007,'And you, be ye fruitful, and multiply; bring forth abundantly in the earth, and multiply therein.'); +INSERT INTO t1(docid,words) VALUES(1009008,'And God spake unto Noah, and to his sons with him, saying,'); +INSERT INTO t1(docid,words) VALUES(1009009,'And I, behold, I establish my covenant with you, and with your seed after you;'); +INSERT INTO t1(docid,words) VALUES(1009010,'And with every living creature that is with you, of the fowl, of the cattle, and of every beast of the earth with you; from all that go out of the ark, to every beast of the earth.'); +INSERT INTO t1(docid,words) VALUES(1009011,'And I will establish my covenant with you, neither shall all flesh be cut off any more by the waters of a flood; neither shall there any more be a flood to destroy the earth.'); +INSERT INTO t1(docid,words) VALUES(1009012,'And God said, This is the token of the covenant which I make between me and you and every living creature that is with you, for perpetual generations:'); +INSERT INTO t1(docid,words) VALUES(1009013,'I do set my bow in the cloud, and it shall be for a token of a covenant between me and the earth.'); +INSERT INTO t1(docid,words) VALUES(1009014,'And it shall come to pass, when I bring a cloud over the earth, that the bow shall be seen in the cloud:'); +INSERT INTO t1(docid,words) VALUES(1009015,'And I will remember my covenant, which is between me and you and every living creature of all flesh; and the waters shall no more become a flood to destroy all flesh.'); +INSERT INTO t1(docid,words) VALUES(1009016,'And the bow shall be in the cloud; and I will look upon it, that I may remember the everlasting covenant between God and every living creature of all flesh that is upon the earth.'); +INSERT INTO t1(docid,words) VALUES(1009017,'And God said unto Noah, This is the token of the covenant, which I have established between me and all flesh that is upon the earth.'); +INSERT INTO t1(docid,words) VALUES(1009018,'And the sons of Noah, that went forth of the ark, were Shem, and Ham, and Japheth: and Ham is the father of Canaan.'); +INSERT INTO t1(docid,words) VALUES(1009019,'These are the three sons of Noah: and of them was the whole earth overspread.'); +INSERT INTO t1(docid,words) VALUES(1009020,'And Noah began to be an husbandman, and he planted a vineyard:'); +INSERT INTO t1(docid,words) VALUES(1009021,'And he drank of the wine, and was drunken; and he was uncovered within his tent.'); +INSERT INTO t1(docid,words) VALUES(1009022,'And Ham, the father of Canaan, saw the nakedness of his father, and told his two brethren without.'); +INSERT INTO t1(docid,words) VALUES(1009023,'And Shem and Japheth took a garment, and laid it upon both their shoulders, and went backward, and covered the nakedness of their father; and their faces were backward, and they saw not their father''s nakedness.'); +INSERT INTO t1(docid,words) VALUES(1009024,'And Noah awoke from his wine, and knew what his younger son had done unto him.'); +INSERT INTO t1(docid,words) VALUES(1009025,'And he said, Cursed be Canaan; a servant of servants shall he be unto his brethren.'); +INSERT INTO t1(docid,words) VALUES(1009026,'And he said, Blessed be the LORD God of Shem; and Canaan shall be his servant.'); +INSERT INTO t1(docid,words) VALUES(1009027,'God shall enlarge Japheth, and he shall dwell in the tents of Shem; and Canaan shall be his servant.'); +INSERT INTO t1(docid,words) VALUES(1009028,'And Noah lived after the flood three hundred and fifty years.'); +INSERT INTO t1(docid,words) VALUES(1009029,'And all the days of Noah were nine hundred and fifty years: and he died.'); +INSERT INTO t1(docid,words) VALUES(1010001,'Now these are the generations of the sons of Noah, Shem, Ham, and Japheth: and unto them were sons born after the flood.'); +INSERT INTO t1(docid,words) VALUES(1010002,'The sons of Japheth; Gomer, and Magog, and Madai, and Javan, and Tubal, and Meshech, and Tiras.'); +INSERT INTO t1(docid,words) VALUES(1010003,'And the sons of Gomer; Ashkenaz, and Riphath, and Togarmah.'); +INSERT INTO t1(docid,words) VALUES(1010004,'And the sons of Javan; Elishah, and Tarshish, Kittim, and Dodanim.'); +INSERT INTO t1(docid,words) VALUES(1010005,'By these were the isles of the Gentiles divided in their lands; every one after his tongue, after their families, in their nations.'); +INSERT INTO t1(docid,words) VALUES(1010006,'And the sons of Ham; Cush, and Mizraim, and Phut, and Canaan.'); +INSERT INTO t1(docid,words) VALUES(1010007,'And the sons of Cush; Seba, and Havilah, and Sabtah, and Raamah, and Sabtechah: and the sons of Raamah; Sheba, and Dedan.'); +INSERT INTO t1(docid,words) VALUES(1010008,'And Cush begat Nimrod: he began to be a mighty one in the earth.'); +INSERT INTO t1(docid,words) VALUES(1010009,'He was a mighty hunter before the LORD: wherefore it is said, Even as Nimrod the mighty hunter before the LORD.'); +INSERT INTO t1(docid,words) VALUES(1010010,'And the beginning of his kingdom was Babel, and Erech, and Accad, and Calneh, in the land of Shinar.'); +INSERT INTO t1(docid,words) VALUES(1010011,'Out of that land went forth Asshur, and builded Nineveh, and the city Rehoboth, and Calah,'); +INSERT INTO t1(docid,words) VALUES(1010012,'And Resen between Nineveh and Calah: the same is a great city.'); +INSERT INTO t1(docid,words) VALUES(1010013,'And Mizraim begat Ludim, and Anamim, and Lehabim, and Naphtuhim,'); +INSERT INTO t1(docid,words) VALUES(1010014,'And Pathrusim, and Casluhim, (out of whom came Philistim,) and Caphtorim.'); +INSERT INTO t1(docid,words) VALUES(1010015,'And Canaan begat Sidon his first born, and Heth,'); +INSERT INTO t1(docid,words) VALUES(1010016,'And the Jebusite, and the Amorite, and the Girgasite,'); +INSERT INTO t1(docid,words) VALUES(1010017,'And the Hivite, and the Arkite, and the Sinite,'); +INSERT INTO t1(docid,words) VALUES(1010018,'And the Arvadite, and the Zemarite, and the Hamathite: and afterward were the families of the Canaanites spread abroad.'); +INSERT INTO t1(docid,words) VALUES(1010019,'And the border of the Canaanites was from Sidon, as thou comest to Gerar, unto Gaza; as thou goest, unto Sodom, and Gomorrah, and Admah, and Zeboim, even unto Lasha.'); +INSERT INTO t1(docid,words) VALUES(1010020,'These are the sons of Ham, after their families, after their tongues, in their countries, and in their nations.'); +INSERT INTO t1(docid,words) VALUES(1010021,'Unto Shem also, the father of all the children of Eber, the brother of Japheth the elder, even to him were children born.'); +INSERT INTO t1(docid,words) VALUES(1010022,'The children of Shem; Elam, and Asshur, and Arphaxad, and Lud, and Aram.'); +INSERT INTO t1(docid,words) VALUES(1010023,'And the children of Aram; Uz, and Hul, and Gether, and Mash.'); +INSERT INTO t1(docid,words) VALUES(1010024,'And Arphaxad begat Salah; and Salah begat Eber.'); +INSERT INTO t1(docid,words) VALUES(1010025,'And unto Eber were born two sons: the name of one was Peleg; for in his days was the earth divided; and his brother''s name was Joktan.'); +INSERT INTO t1(docid,words) VALUES(1010026,'And Joktan begat Almodad, and Sheleph, and Hazarmaveth, and Jerah,'); +INSERT INTO t1(docid,words) VALUES(1010027,'And Hadoram, and Uzal, and Diklah,'); +INSERT INTO t1(docid,words) VALUES(1010028,'And Obal, and Abimael, and Sheba,'); +INSERT INTO t1(docid,words) VALUES(1010029,'And Ophir, and Havilah, and Jobab: all these were the sons of Joktan.'); +INSERT INTO t1(docid,words) VALUES(1010030,'And their dwelling was from Mesha, as thou goest unto Sephar a mount of the east.'); +INSERT INTO t1(docid,words) VALUES(1010031,'These are the sons of Shem, after their families, after their tongues, in their lands, after their nations.'); +INSERT INTO t1(docid,words) VALUES(1010032,'These are the families of the sons of Noah, after their generations, in their nations: and by these were the nations divided in the earth after the flood.'); +INSERT INTO t1(docid,words) VALUES(1011001,'And the whole earth was of one language, and of one speech.'); +INSERT INTO t1(docid,words) VALUES(1011002,'And it came to pass, as they journeyed from the east, that they found a plain in the land of Shinar; and they dwelt there.'); +INSERT INTO t1(docid,words) VALUES(1011003,'And they said one to another, Go to, let us make brick, and burn them thoroughly. And they had brick for stone, and slime had they for morter.'); +INSERT INTO t1(docid,words) VALUES(1011004,'And they said, Go to, let us build us a city and a tower, whose top may reach unto heaven; and let us make us a name, lest we be scattered abroad upon the face of the whole earth.'); +INSERT INTO t1(docid,words) VALUES(1011005,'And the LORD came down to see the city and the tower, which the children of men builded.'); +INSERT INTO t1(docid,words) VALUES(1011006,'And the LORD said, Behold, the people is one, and they have all one language; and this they begin to do: and now nothing will be restrained from them, which they have imagined to do.'); +INSERT INTO t1(docid,words) VALUES(1011007,'Go to, let us go down, and there confound their language, that they may not understand one another''s speech.'); +INSERT INTO t1(docid,words) VALUES(1011008,'So the LORD scattered them abroad from thence upon the face of all the earth: and they left off to build the city.'); +INSERT INTO t1(docid,words) VALUES(1011009,'Therefore is the name of it called Babel; because the LORD did there confound the language of all the earth: and from thence did the LORD scatter them abroad upon the face of all the earth.'); +INSERT INTO t1(docid,words) VALUES(1011010,'These are the generations of Shem: Shem was an hundred years old, and begat Arphaxad two years after the flood:'); +INSERT INTO t1(docid,words) VALUES(1011011,'And Shem lived after he begat Arphaxad five hundred years, and begat sons and daughters.'); +INSERT INTO t1(docid,words) VALUES(1011012,'And Arphaxad lived five and thirty years, and begat Salah:'); +INSERT INTO t1(docid,words) VALUES(1011013,'And Arphaxad lived after he begat Salah four hundred and three years, and begat sons and daughters.'); +INSERT INTO t1(docid,words) VALUES(1011014,'And Salah lived thirty years, and begat Eber:'); +INSERT INTO t1(docid,words) VALUES(1011015,'And Salah lived after he begat Eber four hundred and three years, and begat sons and daughters.'); +INSERT INTO t1(docid,words) VALUES(1011016,'And Eber lived four and thirty years, and begat Peleg:'); +INSERT INTO t1(docid,words) VALUES(1011017,'And Eber lived after he begat Peleg four hundred and thirty years, and begat sons and daughters.'); +INSERT INTO t1(docid,words) VALUES(1011018,'And Peleg lived thirty years, and begat Reu:'); +INSERT INTO t1(docid,words) VALUES(1011019,'And Peleg lived after he begat Reu two hundred and nine years, and begat sons and daughters.'); +INSERT INTO t1(docid,words) VALUES(1011020,'And Reu lived two and thirty years, and begat Serug:'); +INSERT INTO t1(docid,words) VALUES(1011021,'And Reu lived after he begat Serug two hundred and seven years, and begat sons and daughters.'); +INSERT INTO t1(docid,words) VALUES(1011022,'And Serug lived thirty years, and begat Nahor:'); +INSERT INTO t1(docid,words) VALUES(1011023,'And Serug lived after he begat Nahor two hundred years, and begat sons and daughters.'); +INSERT INTO t1(docid,words) VALUES(1011024,'And Nahor lived nine and twenty years, and begat Terah:'); +INSERT INTO t1(docid,words) VALUES(1011025,'And Nahor lived after he begat Terah an hundred and nineteen years, and begat sons and daughters.'); +INSERT INTO t1(docid,words) VALUES(1011026,'And Terah lived seventy years, and begat Abram, Nahor, and Haran.'); +INSERT INTO t1(docid,words) VALUES(1011027,'Now these are the generations of Terah: Terah begat Abram, Nahor, and Haran; and Haran begat Lot.'); +INSERT INTO t1(docid,words) VALUES(1011028,'And Haran died before his father Terah in the land of his nativity, in Ur of the Chaldees.'); +INSERT INTO t1(docid,words) VALUES(1011029,'And Abram and Nahor took them wives: the name of Abram''s wife was Sarai; and the name of Nahor''s wife, Milcah, the daughter of Haran, the father of Milcah, and the father of Iscah.'); +INSERT INTO t1(docid,words) VALUES(1011030,'But Sarai was barren; she had no child.'); +INSERT INTO t1(docid,words) VALUES(1011031,'And Terah took Abram his son, and Lot the son of Haran his son''s son, and Sarai his daughter in law, his son Abram''s wife; and they went forth with them from Ur of the Chaldees, to go into the land of Canaan; and they came unto Haran, and dwelt there.'); +INSERT INTO t1(docid,words) VALUES(1011032,'And the days of Terah were two hundred and five years: and Terah died in Haran.'); +INSERT INTO t1(docid,words) VALUES(1012001,'Now the LORD had said unto Abram, Get thee out of thy country, and from thy kindred, and from thy father''s house, unto a land that I will shew thee:'); +INSERT INTO t1(docid,words) VALUES(1012002,'And I will make of thee a great nation, and I will bless thee, and make thy name great; and thou shalt be a blessing:'); +INSERT INTO t1(docid,words) VALUES(1012003,'And I will bless them that bless thee, and curse him that curseth thee: and in thee shall all families of the earth be blessed.'); +INSERT INTO t1(docid,words) VALUES(1012004,'So Abram departed, as the LORD had spoken unto him; and Lot went with him: and Abram was seventy and five years old when he departed out of Haran.'); +INSERT INTO t1(docid,words) VALUES(1012005,'And Abram took Sarai his wife, and Lot his brother''s son, and all their substance that they had gathered, and the souls that they had gotten in Haran; and they went forth to go into the land of Canaan; and into the land of Canaan they came.'); +INSERT INTO t1(docid,words) VALUES(1012006,'And Abram passed through the land unto the place of Sichem, unto the plain of Moreh. And the Canaanite was then in the land.'); +INSERT INTO t1(docid,words) VALUES(1012007,'And the LORD appeared unto Abram, and said, Unto thy seed will I give this land: and there builded he an altar unto the LORD, who appeared unto him.'); +INSERT INTO t1(docid,words) VALUES(1012008,'And he removed from thence unto a mountain on the east of Bethel, and pitched his tent, having Bethel on the west, and Hai on the east: and there he builded an altar unto the LORD, and called upon the name of the LORD.'); +INSERT INTO t1(docid,words) VALUES(1012009,'And Abram journeyed, going on still toward the south.'); +INSERT INTO t1(docid,words) VALUES(1012010,'And there was a famine in the land: and Abram went down into Egypt to sojourn there; for the famine was grievous in the land.'); +INSERT INTO t1(docid,words) VALUES(1012011,'And it came to pass, when he was come near to enter into Egypt, that he said unto Sarai his wife, Behold now, I know that thou art a fair woman to look upon:'); +INSERT INTO t1(docid,words) VALUES(1012012,'Therefore it shall come to pass, when the Egyptians shall see thee, that they shall say, This is his wife: and they will kill me, but they will save thee alive.'); +INSERT INTO t1(docid,words) VALUES(1012013,'Say, I pray thee, thou art my sister: that it may be well with me for thy sake; and my soul shall live because of thee.'); +INSERT INTO t1(docid,words) VALUES(1012014,'And it came to pass, that, when Abram was come into Egypt, the Egyptians beheld the woman that she was very fair.'); +INSERT INTO t1(docid,words) VALUES(1012015,'The princes also of Pharaoh saw her, and commended her before Pharaoh: and the woman was taken into Pharaoh''s house.'); +INSERT INTO t1(docid,words) VALUES(1012016,'And he entreated Abram well for her sake: and he had sheep, and oxen, and he asses, and menservants, and maidservants, and she asses, and camels.'); +INSERT INTO t1(docid,words) VALUES(1012017,'And the LORD plagued Pharaoh and his house with great plagues because of Sarai Abram''s wife.'); +INSERT INTO t1(docid,words) VALUES(1012018,'And Pharaoh called Abram and said, What is this that thou hast done unto me? why didst thou not tell me that she was thy wife?'); +INSERT INTO t1(docid,words) VALUES(1012019,'Why saidst thou, She is my sister? so I might have taken her to me to wife: now therefore behold thy wife, take her, and go thy way.'); +INSERT INTO t1(docid,words) VALUES(1012020,'And Pharaoh commanded his men concerning him: and they sent him away, and his wife, and all that he had.'); +INSERT INTO t1(docid,words) VALUES(1013001,'And Abram went up out of Egypt, he, and his wife, and all that he had, and Lot with him, into the south.'); +INSERT INTO t1(docid,words) VALUES(1013002,'And Abram was very rich in cattle, in silver, and in gold.'); +INSERT INTO t1(docid,words) VALUES(1013003,'And he went on his journeys from the south even to Bethel, unto the place where his tent had been at the beginning, between Bethel and Hai;'); +INSERT INTO t1(docid,words) VALUES(1013004,'Unto the place of the altar, which he had make there at the first: and there Abram called on the name of the LORD.'); +INSERT INTO t1(docid,words) VALUES(1013005,'And Lot also, which went with Abram, had flocks, and herds, and tents.'); +INSERT INTO t1(docid,words) VALUES(1013006,'And the land was not able to bear them, that they might dwell together: for their substance was great, so that they could not dwell together.'); +INSERT INTO t1(docid,words) VALUES(1013007,'And there was a strife between the herdmen of Abram''s cattle and the herdmen of Lot''s cattle: and the Canaanite and the Perizzite dwelled then in the land.'); +INSERT INTO t1(docid,words) VALUES(1013008,'And Abram said unto Lot, Let there be no strife, I pray thee, between me and thee, and between my herdmen and thy herdmen; for we be brethren.'); +INSERT INTO t1(docid,words) VALUES(1013009,'Is not the whole land before thee? separate thyself, I pray thee, from me: if thou wilt take the left hand, then I will go to the right; or if thou depart to the right hand, then I will go to the left.'); +INSERT INTO t1(docid,words) VALUES(1013010,'And Lot lifted up his eyes, and beheld all the plain of Jordan, that it was well watered every where, before the LORD destroyed Sodom and Gomorrah, even as the garden of the LORD, like the land of Egypt, as thou comest unto Zoar.'); +INSERT INTO t1(docid,words) VALUES(1013011,'Then Lot chose him all the plain of Jordan; and Lot journeyed east: and they separated themselves the one from the other.'); +INSERT INTO t1(docid,words) VALUES(1013012,'Abram dwelled in the land of Canaan, and Lot dwelled in the cities of the plain, and pitched his tent toward Sodom.'); +INSERT INTO t1(docid,words) VALUES(1013013,'But the men of Sodom were wicked and sinners before the LORD exceedingly.'); +INSERT INTO t1(docid,words) VALUES(1013014,'And the LORD said unto Abram, after that Lot was separated from him, Lift up now thine eyes, and look from the place where thou art northward, and southward, and eastward, and westward:'); +INSERT INTO t1(docid,words) VALUES(1013015,'For all the land which thou seest, to thee will I give it, and to thy seed for ever.'); +INSERT INTO t1(docid,words) VALUES(1013016,'And I will make thy seed as the dust of the earth: so that if a man can number the dust of the earth, then shall thy seed also be numbered.'); +INSERT INTO t1(docid,words) VALUES(1013017,'Arise, walk through the land in the length of it and in the breadth of it; for I will give it unto thee.'); +INSERT INTO t1(docid,words) VALUES(1013018,'Then Abram removed his tent, and came and dwelt in the plain of Mamre, which is in Hebron, and built there an altar unto the LORD.'); +INSERT INTO t1(docid,words) VALUES(1014001,'And it came to pass in the days of Amraphel king of Shinar, Arioch king of Ellasar, Chedorlaomer king of Elam, and Tidal king of nations;'); +INSERT INTO t1(docid,words) VALUES(1014002,'That these made war with Bera king of Sodom, and with Birsha king of Gomorrah, Shinab king of Admah, and Shemeber king of Zeboiim, and the king of Bela, which is Zoar.'); +INSERT INTO t1(docid,words) VALUES(1014003,'All these were joined together in the vale of Siddim, which is the salt sea.'); +INSERT INTO t1(docid,words) VALUES(1014004,'Twelve years they served Chedorlaomer, and in the thirteenth year they rebelled.'); +INSERT INTO t1(docid,words) VALUES(1014005,'And in the fourteenth year came Chedorlaomer, and the kings that were with him, and smote the Rephaims in Ashteroth Karnaim, and the Zuzims in Ham, and the Emins in Shaveh Kiriathaim,'); +INSERT INTO t1(docid,words) VALUES(1014006,'And the Horites in their mount Seir, unto Elparan, which is by the wilderness.'); +INSERT INTO t1(docid,words) VALUES(1014007,'And they returned, and came to Enmishpat, which is Kadesh, and smote all the country of the Amalekites, and also the Amorites, that dwelt in Hazezontamar.'); +INSERT INTO t1(docid,words) VALUES(1014008,'And there went out the king of Sodom, and the king of Gomorrah, and the king of Admah, and the king of Zeboiim, and the king of Bela (the same is Zoar;) and they joined battle with them in the vale of Siddim;'); +INSERT INTO t1(docid,words) VALUES(1014009,'With Chedorlaomer the king of Elam, and with Tidal king of nations, and Amraphel king of Shinar, and Arioch king of Ellasar; four kings with five.'); +INSERT INTO t1(docid,words) VALUES(1014010,'And the vale of Siddim was full of slimepits; and the kings of Sodom and Gomorrah fled, and fell there; and they that remained fled to the mountain.'); +INSERT INTO t1(docid,words) VALUES(1014011,'And they took all the goods of Sodom and Gomorrah, and all their victuals, and went their way.'); +INSERT INTO t1(docid,words) VALUES(1014012,'And they took Lot, Abram''s brother''s son, who dwelt in Sodom, and his goods, and departed.'); +INSERT INTO t1(docid,words) VALUES(1014013,'And there came one that had escaped, and told Abram the Hebrew; for he dwelt in the plain of Mamre the Amorite, brother of Eshcol, and brother of Aner: and these were confederate with Abram.'); +INSERT INTO t1(docid,words) VALUES(1014014,'And when Abram heard that his brother was taken captive, he armed his trained servants, born in his own house, three hundred and eighteen, and pursued them unto Dan.'); +INSERT INTO t1(docid,words) VALUES(1014015,'And he divided himself against them, he and his servants, by night, and smote them, and pursued them unto Hobah, which is on the left hand of Damascus.'); +INSERT INTO t1(docid,words) VALUES(1014016,'And he brought back all the goods, and also brought again his brother Lot, and his goods, and the women also, and the people.'); +INSERT INTO t1(docid,words) VALUES(1014017,'And the king of Sodom went out to meet him after his return from the slaughter of Chedorlaomer, and of the kings that were with him, at the valley of Shaveh, which is the king''s dale.'); +INSERT INTO t1(docid,words) VALUES(1014018,'And Melchizedek king of Salem brought forth bread and wine: and he was the priest of the most high God.'); +INSERT INTO t1(docid,words) VALUES(1014019,'And he blessed him, and said, Blessed be Abram of the most high God, possessor of heaven and earth:'); +INSERT INTO t1(docid,words) VALUES(1014020,'And blessed be the most high God, which hath delivered thine enemies into thy hand. And he gave him tithes of all.'); +INSERT INTO t1(docid,words) VALUES(1014021,'And the king of Sodom said unto Abram, Give me the persons, and take the goods to thyself.'); +INSERT INTO t1(docid,words) VALUES(1014022,'And Abram said to the king of Sodom, I have lift up mine hand unto the LORD, the most high God, the possessor of heaven and earth,'); +INSERT INTO t1(docid,words) VALUES(1014023,'That I will not take from a thread even to a shoelatchet, and that I will not take any thing that is thine, lest thou shouldest say, I have made Abram rich:'); +INSERT INTO t1(docid,words) VALUES(1014024,'Save only that which the young men have eaten, and the portion of the men which went with me, Aner, Eshcol, and Mamre; let them take their portion.'); +INSERT INTO t1(docid,words) VALUES(1015001,'After these things the word of the LORD came unto Abram in a vision, saying, Fear not, Abram: I am thy shield, and thy exceeding great reward.'); +INSERT INTO t1(docid,words) VALUES(1015002,'And Abram said, LORD God, what wilt thou give me, seeing I go childless, and the steward of my house is this Eliezer of Damascus?'); +INSERT INTO t1(docid,words) VALUES(1015003,'And Abram said, Behold, to me thou hast given no seed: and, lo, one born in my house is mine heir.'); +INSERT INTO t1(docid,words) VALUES(1015004,'And, behold, the word of the LORD came unto him, saying, This shall not be thine heir; but he that shall come forth out of thine own bowels shall be thine heir.'); +INSERT INTO t1(docid,words) VALUES(1015005,'And he brought him forth abroad, and said, Look now toward heaven, and tell the stars, if thou be able to number them: and he said unto him, So shall thy seed be.'); +INSERT INTO t1(docid,words) VALUES(1015006,'And he believed in the LORD; and he counted it to him for righteousness.'); +INSERT INTO t1(docid,words) VALUES(1015007,'And he said unto him, I am the LORD that brought thee out of Ur of the Chaldees, to give thee this land to inherit it.'); +INSERT INTO t1(docid,words) VALUES(1015008,'And he said, LORD God, whereby shall I know that I shall inherit it?'); +INSERT INTO t1(docid,words) VALUES(1015009,'And he said unto him, Take me an heifer of three years old, and a she goat of three years old, and a ram of three years old, and a turtledove, and a young pigeon.'); +INSERT INTO t1(docid,words) VALUES(1015010,'And he took unto him all these, and divided them in the midst, and laid each piece one against another: but the birds divided he not.'); +INSERT INTO t1(docid,words) VALUES(1015011,'And when the fowls came down upon the carcases, Abram drove them away.'); +INSERT INTO t1(docid,words) VALUES(1015012,'And when the sun was going down, a deep sleep fell upon Abram; and, lo, an horror of great darkness fell upon him.'); +INSERT INTO t1(docid,words) VALUES(1015013,'And he said unto Abram, Know of a surety that thy seed shall be a stranger in a land that is not their''s, and shall serve them; and they shall afflict them four hundred years;'); +INSERT INTO t1(docid,words) VALUES(1015014,'And also that nation, whom they shall serve, will I judge: and afterward shall they come out with great substance.'); +INSERT INTO t1(docid,words) VALUES(1015015,'And thou shalt go to thy fathers in peace; thou shalt be buried in a good old age.'); +INSERT INTO t1(docid,words) VALUES(1015016,'But in the fourth generation they shall come hither again: for the iniquity of the Amorites is not yet full.'); +INSERT INTO t1(docid,words) VALUES(1015017,'And it came to pass, that, when the sun went down, and it was dark, behold a smoking furnace, and a burning lamp that passed between those pieces.'); +INSERT INTO t1(docid,words) VALUES(1015018,'In the same day the LORD made a covenant with Abram, saying, Unto thy seed have I given this land, from the river of Egypt unto the great river, the river Euphrates:'); +INSERT INTO t1(docid,words) VALUES(1015019,'The Kenites, and the Kenizzites, and the Kadmonites,'); +INSERT INTO t1(docid,words) VALUES(1015020,'And the Hittites, and the Perizzites, and the Rephaims,'); +INSERT INTO t1(docid,words) VALUES(1015021,'And the Amorites, and the Canaanites, and the Girgashites, and the Jebusites.'); +INSERT INTO t1(docid,words) VALUES(1016001,'Now Sarai Abram''s wife bare him no children: and she had an handmaid, an Egyptian, whose name was Hagar.'); +INSERT INTO t1(docid,words) VALUES(1016002,'And Sarai said unto Abram, Behold now, the LORD hath restrained me from bearing: I pray thee, go in unto my maid; it may be that I may obtain children by her. And Abram hearkened to the voice of Sarai.'); +INSERT INTO t1(docid,words) VALUES(1016003,'And Sarai Abram''s wife took Hagar her maid the Egyptian, after Abram had dwelt ten years in the land of Canaan, and gave her to her husband Abram to be his wife.'); +INSERT INTO t1(docid,words) VALUES(1016004,'And he went in unto Hagar, and she conceived: and when she saw that she had conceived, her mistress was despised in her eyes.'); +INSERT INTO t1(docid,words) VALUES(1016005,'And Sarai said unto Abram, My wrong be upon thee: I have given my maid into thy bosom; and when she saw that she had conceived, I was despised in her eyes: the LORD judge between me and thee.'); +INSERT INTO t1(docid,words) VALUES(1016006,'But Abram said unto Sarai, Behold, thy maid is in thine hand; do to her as it pleaseth thee. And when Sarai dealt hardly with her, she fled from her face.'); +INSERT INTO t1(docid,words) VALUES(1016007,'And the angel of the LORD found her by a fountain of water in the wilderness, by the fountain in the way to Shur.'); +INSERT INTO t1(docid,words) VALUES(1016008,'And he said, Hagar, Sarai''s maid, whence camest thou? and whither wilt thou go? And she said, I flee from the face of my mistress Sarai.'); +INSERT INTO t1(docid,words) VALUES(1016009,'And the angel of the LORD said unto her, Return to thy mistress, and submit thyself under her hands.'); +INSERT INTO t1(docid,words) VALUES(1016010,'And the angel of the LORD said unto her, I will multiply thy seed exceedingly, that it shall not be numbered for multitude.'); +INSERT INTO t1(docid,words) VALUES(1016011,'And the angel of the LORD said unto her, Behold, thou art with child and shalt bear a son, and shalt call his name Ishmael; because the LORD hath heard thy affliction.'); +INSERT INTO t1(docid,words) VALUES(1016012,'And he will be a wild man; his hand will be against every man, and every man''s hand against him; and he shall dwell in the presence of all his brethren.'); +INSERT INTO t1(docid,words) VALUES(1016013,'And she called the name of the LORD that spake unto her, Thou God seest me: for she said, Have I also here looked after him that seeth me?'); +INSERT INTO t1(docid,words) VALUES(1016014,'Wherefore the well was called Beerlahairoi; behold, it is between Kadesh and Bered.'); +INSERT INTO t1(docid,words) VALUES(1016015,'And Hagar bare Abram a son: and Abram called his son''s name, which Hagar bare, Ishmael.'); +INSERT INTO t1(docid,words) VALUES(1016016,'And Abram was fourscore and six years old, when Hagar bare Ishmael to Abram.'); +INSERT INTO t1(docid,words) VALUES(1017001,'And when Abram was ninety years old and nine, the LORD appeared to Abram, and said unto him, I am the Almighty God; walk before me, and be thou perfect.'); +INSERT INTO t1(docid,words) VALUES(1017002,'And I will make my covenant between me and thee, and will multiply thee exceedingly.'); +INSERT INTO t1(docid,words) VALUES(1017003,'And Abram fell on his face: and God talked with him, saying,'); +INSERT INTO t1(docid,words) VALUES(1017004,'As for me, behold, my covenant is with thee, and thou shalt be a father of many nations.'); +INSERT INTO t1(docid,words) VALUES(1017005,'Neither shall thy name any more be called Abram, but thy name shall be Abraham; for a father of many nations have I made thee.'); +INSERT INTO t1(docid,words) VALUES(1017006,'And I will make thee exceeding fruitful, and I will make nations of thee, and kings shall come out of thee.'); +INSERT INTO t1(docid,words) VALUES(1017007,'And I will establish my covenant between me and thee and thy seed after thee in their generations for an everlasting covenant, to be a God unto thee, and to thy seed after thee.'); +INSERT INTO t1(docid,words) VALUES(1017008,'And I will give unto thee, and to thy seed after thee, the land wherein thou art a stranger, all the land of Canaan, for an everlasting possession; and I will be their God.'); +INSERT INTO t1(docid,words) VALUES(1017009,'And God said unto Abraham, Thou shalt keep my covenant therefore, thou, and thy seed after thee in their generations.'); +INSERT INTO t1(docid,words) VALUES(1017010,'This is my covenant, which ye shall keep, between me and you and thy seed after thee; Every man child among you shall be circumcised.'); +INSERT INTO t1(docid,words) VALUES(1017011,'And ye shall circumcise the flesh of your foreskin; and it shall be a token of the covenant betwixt me and you.'); +INSERT INTO t1(docid,words) VALUES(1017012,'And he that is eight days old shall be circumcised among you, every man child in your generations, he that is born in the house, or bought with money of any stranger, which is not of thy seed.'); +INSERT INTO t1(docid,words) VALUES(1017013,'He that is born in thy house, and he that is bought with thy money, must needs be circumcised: and my covenant shall be in your flesh for an everlasting covenant.'); +INSERT INTO t1(docid,words) VALUES(1017014,'And the uncircumcised man child whose flesh of his foreskin is not circumcised, that soul shall be cut off from his people; he hath broken my covenant.'); +INSERT INTO t1(docid,words) VALUES(1017015,'And God said unto Abraham, As for Sarai thy wife, thou shalt not call her name Sarai, but Sarah shall her name be.'); +INSERT INTO t1(docid,words) VALUES(1017016,'And I will bless her, and give thee a son also of her: yea, I will bless her, and she shall be a mother of nations; kings of people shall be of her.'); +INSERT INTO t1(docid,words) VALUES(1017017,'Then Abraham fell upon his face, and laughed, and said in his heart, Shall a child be born unto him that is an hundred years old? and shall Sarah, that is ninety years old, bear?'); +INSERT INTO t1(docid,words) VALUES(1017018,'And Abraham said unto God, O that Ishmael might live before thee!'); +INSERT INTO t1(docid,words) VALUES(1017019,'And God said, Sarah thy wife shall bear thee a son indeed; and thou shalt call his name Isaac: and I will establish my covenant with him for an everlasting covenant, and with his seed after him.'); +INSERT INTO t1(docid,words) VALUES(1017020,'And as for Ishmael, I have heard thee: Behold, I have blessed him, and will make him fruitful, and will multiply him exceedingly; twelve princes shall he beget, and I will make him a great nation.'); +INSERT INTO t1(docid,words) VALUES(1017021,'But my covenant will I establish with Isaac, which Sarah shall bear unto thee at this set time in the next year.'); +INSERT INTO t1(docid,words) VALUES(1017022,'And he left off talking with him, and God went up from Abraham.'); +INSERT INTO t1(docid,words) VALUES(1017023,'And Abraham took Ishmael his son, and all that were born in his house, and all that were bought with his money, every male among the men of Abraham''s house; and circumcised the flesh of their foreskin in the selfsame day, as God had said unto him.'); +INSERT INTO t1(docid,words) VALUES(1017024,'And Abraham was ninety years old and nine, when he was circumcised in the flesh of his foreskin.'); +INSERT INTO t1(docid,words) VALUES(1017025,'And Ishmael his son was thirteen years old, when he was circumcised in the flesh of his foreskin.'); +INSERT INTO t1(docid,words) VALUES(1017026,'In the selfsame day was Abraham circumcised, and Ishmael his son.'); +INSERT INTO t1(docid,words) VALUES(1017027,'And all the men of his house, born in the house, and bought with money of the stranger, were circumcised with him.'); +INSERT INTO t1(docid,words) VALUES(1018001,'And the LORD appeared unto him in the plains of Mamre: and he sat in the tent door in the heat of the day;'); +INSERT INTO t1(docid,words) VALUES(1018002,'And he lift up his eyes and looked, and, lo, three men stood by him: and when he saw them, he ran to meet them from the tent door, and bowed himself toward the ground,'); +INSERT INTO t1(docid,words) VALUES(1018003,'And said, My LORD, if now I have found favour in thy sight, pass not away, I pray thee, from thy servant:'); +INSERT INTO t1(docid,words) VALUES(1018004,'Let a little water, I pray you, be fetched, and wash your feet, and rest yourselves under the tree:'); +INSERT INTO t1(docid,words) VALUES(1018005,'And I will fetch a morsel of bread, and comfort ye your hearts; after that ye shall pass on: for therefore are ye come to your servant. And they said, So do, as thou hast said.'); +INSERT INTO t1(docid,words) VALUES(1018006,'And Abraham hastened into the tent unto Sarah, and said, Make ready quickly three measures of fine meal, knead it, and make cakes upon the hearth.'); +INSERT INTO t1(docid,words) VALUES(1018007,'And Abraham ran unto the herd, and fetcht a calf tender and good, and gave it unto a young man; and he hasted to dress it.'); +INSERT INTO t1(docid,words) VALUES(1018008,'And he took butter, and milk, and the calf which he had dressed, and set it before them; and he stood by them under the tree, and they did eat.'); +INSERT INTO t1(docid,words) VALUES(1018009,'And they said unto him, Where is Sarah thy wife? And he said, Behold, in the tent.'); +INSERT INTO t1(docid,words) VALUES(1018010,'And he said, I will certainly return unto thee according to the time of life; and, lo, Sarah thy wife shall have a son. And Sarah heard it in the tent door, which was behind him.'); +INSERT INTO t1(docid,words) VALUES(1018011,'Now Abraham and Sarah were old and well stricken in age; and it ceased to be with Sarah after the manner of women.'); +INSERT INTO t1(docid,words) VALUES(1018012,'Therefore Sarah laughed within herself, saying, After I am waxed old shall I have pleasure, my lord being old also?'); +INSERT INTO t1(docid,words) VALUES(1018013,'And the LORD said unto Abraham, Wherefore did Sarah laugh, saying, Shall I of a surety bear a child, which am old?'); +INSERT INTO t1(docid,words) VALUES(1018014,'Is any thing too hard for the LORD? At the time appointed I will return unto thee, according to the time of life, and Sarah shall have a son.'); +INSERT INTO t1(docid,words) VALUES(1018015,'Then Sarah denied, saying, I laughed not; for she was afraid. And he said, Nay; but thou didst laugh.'); +INSERT INTO t1(docid,words) VALUES(1018016,'And the men rose up from thence, and looked toward Sodom: and Abraham went with them to bring them on the way.'); +INSERT INTO t1(docid,words) VALUES(1018017,'And the LORD said, Shall I hide from Abraham that thing which I do;'); +INSERT INTO t1(docid,words) VALUES(1018018,'Seeing that Abraham shall surely become a great and mighty nation, and all the nations of the earth shall be blessed in him?'); +INSERT INTO t1(docid,words) VALUES(1018019,'For I know him, that he will command his children and his household after him, and they shall keep the way of the LORD, to do justice and judgment; that the LORD may bring upon Abraham that which he hath spoken of him.'); +INSERT INTO t1(docid,words) VALUES(1018020,'And the LORD said, Because the cry of Sodom and Gomorrah is great, and because their sin is very grievous;'); +INSERT INTO t1(docid,words) VALUES(1018021,'I will go down now, and see whether they have done altogether according to the cry of it, which is come unto me; and if not, I will know.'); +INSERT INTO t1(docid,words) VALUES(1018022,'And the men turned their faces from thence, and went toward Sodom: but Abraham stood yet before the LORD.'); +INSERT INTO t1(docid,words) VALUES(1018023,'And Abraham drew near, and said, Wilt thou also destroy the righteous with the wicked?'); +INSERT INTO t1(docid,words) VALUES(1018024,'Peradventure there be fifty righteous within the city: wilt thou also destroy and not spare the place for the fifty righteous that are therein?'); +INSERT INTO t1(docid,words) VALUES(1018025,'That be far from thee to do after this manner, to slay the righteous with the wicked: and that the righteous should be as the wicked, that be far from thee: Shall not the Judge of all the earth do right?'); +INSERT INTO t1(docid,words) VALUES(1018026,'And the LORD said, If I find in Sodom fifty righteous within the city, then I will spare all the place for their sakes.'); +INSERT INTO t1(docid,words) VALUES(1018027,'And Abraham answered and said, Behold now, I have taken upon me to speak unto the LORD, which am but dust and ashes:'); +INSERT INTO t1(docid,words) VALUES(1018028,'Peradventure there shall lack five of the fifty righteous: wilt thou destroy all the city for lack of five? And he said, If I find there forty and five, I will not destroy it.'); +INSERT INTO t1(docid,words) VALUES(1018029,'And he spake unto him yet again, and said, Peradventure there shall be forty found there. And he said, I will not do it for forty''s sake.'); +INSERT INTO t1(docid,words) VALUES(1018030,'And he said unto him, Oh let not the LORD be angry, and I will speak: Peradventure there shall thirty be found there. And he said, I will not do it, if I find thirty there.'); +INSERT INTO t1(docid,words) VALUES(1018031,'And he said, Behold now, I have taken upon me to speak unto the LORD: Peradventure there shall be twenty found there. And he said, I will not destroy it for twenty''s sake.'); +INSERT INTO t1(docid,words) VALUES(1018032,'And he said, Oh let not the LORD be angry, and I will speak yet but this once: Peradventure ten shall be found there. And he said, I will not destroy it for ten''s sake.'); +INSERT INTO t1(docid,words) VALUES(1018033,'And the LORD went his way, as soon as he had left communing with Abraham: and Abraham returned unto his place.'); +INSERT INTO t1(docid,words) VALUES(1019001,'And there came two angels to Sodom at even; and Lot sat in the gate of Sodom: and Lot seeing them rose up to meet them; and he bowed himself with his face toward the ground;'); +INSERT INTO t1(docid,words) VALUES(1019002,'And he said, Behold now, my lords, turn in, I pray you, into your servant''s house, and tarry all night, and wash your feet, and ye shall rise up early, and go on your ways. And they said, Nay; but we will abide in the street all night.'); +INSERT INTO t1(docid,words) VALUES(1019003,'And he pressed upon them greatly; and they turned in unto him, and entered into his house; and he made them a feast, and did bake unleavened bread, and they did eat.'); +INSERT INTO t1(docid,words) VALUES(1019004,'But before they lay down, the men of the city, even the men of Sodom, compassed the house round, both old and young, all the people from every quarter:'); +INSERT INTO t1(docid,words) VALUES(1019005,'And they called unto Lot, and said unto him, Where are the men which came in to thee this night? bring them out unto us, that we may know them.'); +INSERT INTO t1(docid,words) VALUES(1019006,'And Lot went out at the door unto them, and shut the door after him,'); +INSERT INTO t1(docid,words) VALUES(1019007,'And said, I pray you, brethren, do not so wickedly.'); +INSERT INTO t1(docid,words) VALUES(1019008,'Behold now, I have two daughters which have not known man; let me, I pray you, bring them out unto you, and do ye to them as is good in your eyes: only unto these men do nothing; for therefore came they under the shadow of my roof.'); +INSERT INTO t1(docid,words) VALUES(1019009,'And they said, Stand back. And they said again, This one fellow came in to sojourn, and he will needs be a judge: now will we deal worse with thee, than with them. And they pressed sore upon the man, even Lot, and came near to break the door.'); +INSERT INTO t1(docid,words) VALUES(1019010,'But the men put forth their hand, and pulled Lot into the house to them, and shut to the door.'); +INSERT INTO t1(docid,words) VALUES(1019011,'And they smote the men that were at the door of the house with blindness, both small and great: so that they wearied themselves to find the door.'); +INSERT INTO t1(docid,words) VALUES(1019012,'And the men said unto Lot, Hast thou here any besides? son in law, and thy sons, and thy daughters, and whatsoever thou hast in the city, bring them out of this place:'); +INSERT INTO t1(docid,words) VALUES(1019013,'For we will destroy this place, because the cry of them is waxen great before the face of the LORD; and the LORD hath sent us to destroy it.'); +INSERT INTO t1(docid,words) VALUES(1019014,'And Lot went out, and spake unto his sons in law, which married his daughters, and said, Up, get you out of this place; for the LORD will destroy this city. But he seemed as one that mocked unto his sons in law.'); +INSERT INTO t1(docid,words) VALUES(1019015,'And when the morning arose, then the angels hastened Lot, saying, Arise, take thy wife, and thy two daughters, which are here; lest thou be consumed in the iniquity of the city.'); +INSERT INTO t1(docid,words) VALUES(1019016,'And while he lingered, the men laid hold upon his hand, and upon the hand of his wife, and upon the hand of his two daughters; the LORD being merciful unto him: and they brought him forth, and set him without the city.'); +INSERT INTO t1(docid,words) VALUES(1019017,'And it came to pass, when they had brought them forth abroad, that he said, Escape for thy life; look not behind thee, neither stay thou in all the plain; escape to the mountain, lest thou be consumed.'); +INSERT INTO t1(docid,words) VALUES(1019018,'And Lot said unto them, Oh, not so, my LORD:'); +INSERT INTO t1(docid,words) VALUES(1019019,'Behold now, thy servant hath found grace in thy sight, and thou hast magnified thy mercy, which thou hast shewed unto me in saving my life; and I cannot escape to the mountain, lest some evil take me, and I die:'); +INSERT INTO t1(docid,words) VALUES(1019020,'Behold now, this city is near to flee unto, and it is a little one: Oh, let me escape thither, (is it not a little one?) and my soul shall live.'); +INSERT INTO t1(docid,words) VALUES(1019021,'And he said unto him, See, I have accepted thee concerning this thing also, that I will not overthrow this city, for the which thou hast spoken.'); +INSERT INTO t1(docid,words) VALUES(1019022,'Haste thee, escape thither; for I cannot do anything till thou be come thither. Therefore the name of the city was called Zoar.'); +INSERT INTO t1(docid,words) VALUES(1019023,'The sun was risen upon the earth when Lot entered into Zoar.'); +INSERT INTO t1(docid,words) VALUES(1019024,'Then the LORD rained upon Sodom and upon Gomorrah brimstone and fire from the LORD out of heaven;'); +INSERT INTO t1(docid,words) VALUES(1019025,'And he overthrew those cities, and all the plain, and all the inhabitants of the cities, and that which grew upon the ground.'); +INSERT INTO t1(docid,words) VALUES(1019026,'But his wife looked back from behind him, and she became a pillar of salt.'); +INSERT INTO t1(docid,words) VALUES(1019027,'And Abraham gat up early in the morning to the place where he stood before the LORD:'); +INSERT INTO t1(docid,words) VALUES(1019028,'And he looked toward Sodom and Gomorrah, and toward all the land of the plain, and beheld, and, lo, the smoke of the country went up as the smoke of a furnace.'); +INSERT INTO t1(docid,words) VALUES(1019029,'And it came to pass, when God destroyed the cities of the plain, that God remembered Abraham, and sent Lot out of the midst of the overthrow, when he overthrew the cities in the which Lot dwelt.'); +INSERT INTO t1(docid,words) VALUES(1019030,'And Lot went up out of Zoar, and dwelt in the mountain, and his two daughters with him; for he feared to dwell in Zoar: and he dwelt in a cave, he and his two daughters.'); +INSERT INTO t1(docid,words) VALUES(1019031,'And the firstborn said unto the younger, Our father is old, and there is not a man in the earth to come in unto us after the manner of all the earth:'); +INSERT INTO t1(docid,words) VALUES(1019032,'Come, let us make our father drink wine, and we will lie with him, that we may preserve seed of our father.'); +INSERT INTO t1(docid,words) VALUES(1019033,'And they made their father drink wine that night: and the firstborn went in, and lay with her father; and he perceived not when she lay down, nor when she arose.'); +INSERT INTO t1(docid,words) VALUES(1019034,'And it came to pass on the morrow, that the firstborn said unto the younger, Behold, I lay yesternight with my father: let us make him drink wine this night also; and go thou in, and lie with him, that we may preserve seed of our father.'); +INSERT INTO t1(docid,words) VALUES(1019035,'And they made their father drink wine that night also: and the younger arose, and lay with him; and he perceived not when she lay down, nor when she arose.'); +INSERT INTO t1(docid,words) VALUES(1019036,'Thus were both the daughters of Lot with child by their father.'); +INSERT INTO t1(docid,words) VALUES(1019037,'And the first born bare a son, and called his name Moab: the same is the father of the Moabites unto this day.'); +INSERT INTO t1(docid,words) VALUES(1019038,'And the younger, she also bare a son, and called his name Benammi: the same is the father of the children of Ammon unto this day.'); +INSERT INTO t1(docid,words) VALUES(1020001,'And Abraham journeyed from thence toward the south country, and dwelled between Kadesh and Shur, and sojourned in Gerar.'); +INSERT INTO t1(docid,words) VALUES(1020002,'And Abraham said of Sarah his wife, She is my sister: and Abimelech king of Gerar sent, and took Sarah.'); +INSERT INTO t1(docid,words) VALUES(1020003,'But God came to Abimelech in a dream by night, and said to him, Behold, thou art but a dead man, for the woman which thou hast taken; for she is a man''s wife.'); +INSERT INTO t1(docid,words) VALUES(1020004,'But Abimelech had not come near her: and he said, LORD, wilt thou slay also a righteous nation?'); +INSERT INTO t1(docid,words) VALUES(1020005,'Said he not unto me, She is my sister? and she, even she herself said, He is my brother: in the integrity of my heart and innocency of my hands have I done this.'); +INSERT INTO t1(docid,words) VALUES(1020006,'And God said unto him in a dream, Yea, I know that thou didst this in the integrity of thy heart; for I also withheld thee from sinning against me: therefore suffered I thee not to touch her.'); +INSERT INTO t1(docid,words) VALUES(1020007,'Now therefore restore the man his wife; for he is a prophet, and he shall pray for thee, and thou shalt live: and if thou restore her not, know thou that thou shalt surely die, thou, and all that are thine.'); +INSERT INTO t1(docid,words) VALUES(1020008,'Therefore Abimelech rose early in the morning, and called all his servants, and told all these things in their ears: and the men were sore afraid.'); +INSERT INTO t1(docid,words) VALUES(1020009,'Then Abimelech called Abraham, and said unto him, What hast thou done unto us? and what have I offended thee, that thou hast brought on me and on my kingdom a great sin? thou hast done deeds unto me that ought not to be done.'); +INSERT INTO t1(docid,words) VALUES(1020010,'And Abimelech said unto Abraham, What sawest thou, that thou hast done this thing?'); +INSERT INTO t1(docid,words) VALUES(1020011,'And Abraham said, Because I thought, Surely the fear of God is not in this place; and they will slay me for my wife''s sake.'); +INSERT INTO t1(docid,words) VALUES(1020012,'And yet indeed she is my sister; she is the daughter of my father, but not the daughter of my mother; and she became my wife.'); +INSERT INTO t1(docid,words) VALUES(1020013,'And it came to pass, when God caused me to wander from my father''s house, that I said unto her, This is thy kindness which thou shalt shew unto me; at every place whither we shall come, say of me, He is my brother.'); +INSERT INTO t1(docid,words) VALUES(1020014,'And Abimelech took sheep, and oxen, and menservants, and womenservants, and gave them unto Abraham, and restored him Sarah his wife.'); +INSERT INTO t1(docid,words) VALUES(1020015,'And Abimelech said, Behold, my land is before thee: dwell where it pleaseth thee.'); +INSERT INTO t1(docid,words) VALUES(1020016,'And unto Sarah he said, Behold, I have given thy brother a thousand pieces of silver: behold, he is to thee a covering of the eyes, unto all that are with thee, and with all other: thus she was reproved.'); +INSERT INTO t1(docid,words) VALUES(1020017,'So Abraham prayed unto God: and God healed Abimelech, and his wife, and his maidservants; and they bare children.'); +INSERT INTO t1(docid,words) VALUES(1020018,'For the LORD had fast closed up all the wombs of the house of Abimelech, because of Sarah Abraham''s wife.'); +INSERT INTO t1(docid,words) VALUES(1021001,'And the LORD visited Sarah as he had said, and the LORD did unto Sarah as he had spoken.'); +INSERT INTO t1(docid,words) VALUES(1021002,'For Sarah conceived, and bare Abraham a son in his old age, at the set time of which God had spoken to him.'); +INSERT INTO t1(docid,words) VALUES(1021003,'And Abraham called the name of his son that was born unto him, whom Sarah bare to him, Isaac.'); +INSERT INTO t1(docid,words) VALUES(1021004,'And Abraham circumcised his son Isaac being eight days old, as God had commanded him.'); +INSERT INTO t1(docid,words) VALUES(1021005,'And Abraham was an hundred years old, when his son Isaac was born unto him.'); +INSERT INTO t1(docid,words) VALUES(1021006,'And Sarah said, God hath made me to laugh, so that all that hear will laugh with me.'); +INSERT INTO t1(docid,words) VALUES(1021007,'And she said, Who would have said unto Abraham, that Sarah should have given children suck? for I have born him a son in his old age.'); +INSERT INTO t1(docid,words) VALUES(1021008,'And the child grew, and was weaned: and Abraham made a great feast the same day that Isaac was weaned.'); +INSERT INTO t1(docid,words) VALUES(1021009,'And Sarah saw the son of Hagar the Egyptian, which she had born unto Abraham, mocking.'); +INSERT INTO t1(docid,words) VALUES(1021010,'Wherefore she said unto Abraham, Cast out this bondwoman and her son: for the son of this bondwoman shall not be heir with my son, even with Isaac.'); +INSERT INTO t1(docid,words) VALUES(1021011,'And the thing was very grievous in Abraham''s sight because of his son.'); +INSERT INTO t1(docid,words) VALUES(1021012,'And God said unto Abraham, Let it not be grievous in thy sight because of the lad, and because of thy bondwoman; in all that Sarah hath said unto thee, hearken unto her voice; for in Isaac shall thy seed be called.'); +INSERT INTO t1(docid,words) VALUES(1021013,'And also of the son of the bondwoman will I make a nation, because he is thy seed.'); +INSERT INTO t1(docid,words) VALUES(1021014,'And Abraham rose up early in the morning, and took bread, and a bottle of water, and gave it unto Hagar, putting it on her shoulder, and the child, and sent her away: and she departed, and wandered in the wilderness of Beersheba.'); +INSERT INTO t1(docid,words) VALUES(1021015,'And the water was spent in the bottle, and she cast the child under one of the shrubs.'); +INSERT INTO t1(docid,words) VALUES(1021016,'And she went, and sat her down over against him a good way off, as it were a bow shot: for she said, Let me not see the death of the child. And she sat over against him, and lift up her voice, and wept.'); +INSERT INTO t1(docid,words) VALUES(1021017,'And God heard the voice of the lad; and the angel of God called to Hagar out of heaven, and said unto her, What aileth thee, Hagar? fear not; for God hath heard the voice of the lad where he is.'); +INSERT INTO t1(docid,words) VALUES(1021018,'Arise, lift up the lad, and hold him in thine hand; for I will make him a great nation.'); +INSERT INTO t1(docid,words) VALUES(1021019,'And God opened her eyes, and she saw a well of water; and she went, and filled the bottle with water, and gave the lad drink.'); +INSERT INTO t1(docid,words) VALUES(1021020,'And God was with the lad; and he grew, and dwelt in the wilderness, and became an archer.'); +INSERT INTO t1(docid,words) VALUES(1021021,'And he dwelt in the wilderness of Paran: and his mother took him a wife out of the land of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1021022,'And it came to pass at that time, that Abimelech and Phichol the chief captain of his host spake unto Abraham, saying, God is with thee in all that thou doest:'); +INSERT INTO t1(docid,words) VALUES(1021023,'Now therefore swear unto me here by God that thou wilt not deal falsely with me, nor with my son, nor with my son''s son: but according to the kindness that I have done unto thee, thou shalt do unto me, and to the land wherein thou hast sojourned.'); +INSERT INTO t1(docid,words) VALUES(1021024,'And Abraham said, I will swear.'); +INSERT INTO t1(docid,words) VALUES(1021025,'And Abraham reproved Abimelech because of a well of water, which Abimelech''s servants had violently taken away.'); +INSERT INTO t1(docid,words) VALUES(1021026,'And Abimelech said, I wot not who hath done this thing; neither didst thou tell me, neither yet heard I of it, but to day.'); +INSERT INTO t1(docid,words) VALUES(1021027,'And Abraham took sheep and oxen, and gave them unto Abimelech; and both of them made a covenant.'); +INSERT INTO t1(docid,words) VALUES(1021028,'And Abraham set seven ewe lambs of the flock by themselves.'); +INSERT INTO t1(docid,words) VALUES(1021029,'And Abimelech said unto Abraham, What mean these seven ewe lambs which thou hast set by themselves?'); +INSERT INTO t1(docid,words) VALUES(1021030,'And he said, For these seven ewe lambs shalt thou take of my hand, that they may be a witness unto me, that I have digged this well.'); +INSERT INTO t1(docid,words) VALUES(1021031,'Wherefore he called that place Beersheba; because there they sware both of them.'); +INSERT INTO t1(docid,words) VALUES(1021032,'Thus they made a covenant at Beersheba: then Abimelech rose up, and Phichol the chief captain of his host, and they returned into the land of the Philistines.'); +INSERT INTO t1(docid,words) VALUES(1021033,'And Abraham planted a grove in Beersheba, and called there on the name of the LORD, the everlasting God.'); +INSERT INTO t1(docid,words) VALUES(1021034,'And Abraham sojourned in the Philistines'' land many days.'); +INSERT INTO t1(docid,words) VALUES(1022001,'And it came to pass after these things, that God did tempt Abraham, and said unto him, Abraham: and he said, Behold, here I am.'); +INSERT INTO t1(docid,words) VALUES(1022002,'And he said, Take now thy son, thine only son Isaac, whom thou lovest, and get thee into the land of Moriah; and offer him there for a burnt offering upon one of the mountains which I will tell thee of.'); +INSERT INTO t1(docid,words) VALUES(1022003,'And Abraham rose up early in the morning, and saddled his ass, and took two of his young men with him, and Isaac his son, and clave the wood for the burnt offering, and rose up, and went unto the place of which God had told him.'); +INSERT INTO t1(docid,words) VALUES(1022004,'Then on the third day Abraham lifted up his eyes, and saw the place afar off.'); +INSERT INTO t1(docid,words) VALUES(1022005,'And Abraham said unto his young men, Abide ye here with the ass; and I and the lad will go yonder and worship, and come again to you.'); +INSERT INTO t1(docid,words) VALUES(1022006,'And Abraham took the wood of the burnt offering, and laid it upon Isaac his son; and he took the fire in his hand, and a knife; and they went both of them together.'); +INSERT INTO t1(docid,words) VALUES(1022007,'And Isaac spake unto Abraham his father, and said, My father: and he said, Here am I, my son. And he said, Behold the fire and the wood: but where is the lamb for a burnt offering?'); +INSERT INTO t1(docid,words) VALUES(1022008,'And Abraham said, My son, God will provide himself a lamb for a burnt offering: so they went both of them together.'); +INSERT INTO t1(docid,words) VALUES(1022009,'And they came to the place which God had told him of; and Abraham built an altar there, and laid the wood in order, and bound Isaac his son, and laid him on the altar upon the wood.'); +INSERT INTO t1(docid,words) VALUES(1022010,'And Abraham stretched forth his hand, and took the knife to slay his son.'); +INSERT INTO t1(docid,words) VALUES(1022011,'And the angel of the LORD called unto him out of heaven, and said, Abraham, Abraham: and he said, Here am I.'); +INSERT INTO t1(docid,words) VALUES(1022012,'And he said, Lay not thine hand upon the lad, neither do thou any thing unto him: for now I know that thou fearest God, seeing thou hast not withheld thy son, thine only son from me.'); +INSERT INTO t1(docid,words) VALUES(1022013,'And Abraham lifted up his eyes, and looked, and behold behind him a ram caught in a thicket by his horns: and Abraham went and took the ram, and offered him up for a burnt offering in the stead of his son.'); +INSERT INTO t1(docid,words) VALUES(1022014,'And Abraham called the name of that place Jehovahjireh: as it is said to this day, In the mount of the LORD it shall be seen.'); +INSERT INTO t1(docid,words) VALUES(1022015,'And the angel of the LORD called unto Abraham out of heaven the second time,'); +INSERT INTO t1(docid,words) VALUES(1022016,'And said, By myself have I sworn, saith the LORD, for because thou hast done this thing, and hast not withheld thy son, thine only son:'); +INSERT INTO t1(docid,words) VALUES(1022017,'That in blessing I will bless thee, and in multiplying I will multiply thy seed as the stars of the heaven, and as the sand which is upon the sea shore; and thy seed shall possess the gate of his enemies;'); +INSERT INTO t1(docid,words) VALUES(1022018,'And in thy seed shall all the nations of the earth be blessed; because thou hast obeyed my voice.'); +INSERT INTO t1(docid,words) VALUES(1022019,'So Abraham returned unto his young men, and they rose up and went together to Beersheba; and Abraham dwelt at Beersheba.'); +INSERT INTO t1(docid,words) VALUES(1022020,'And it came to pass after these things, that it was told Abraham, saying, Behold, Milcah, she hath also born children unto thy brother Nahor;'); +INSERT INTO t1(docid,words) VALUES(1022021,'Huz his firstborn, and Buz his brother, and Kemuel the father of Aram,'); +INSERT INTO t1(docid,words) VALUES(1022022,'And Chesed, and Hazo, and Pildash, and Jidlaph, and Bethuel.'); +INSERT INTO t1(docid,words) VALUES(1022023,'And Bethuel begat Rebekah: these eight Milcah did bear to Nahor, Abraham''s brother.'); +INSERT INTO t1(docid,words) VALUES(1022024,'And his concubine, whose name was Reumah, she bare also Tebah, and Gaham, and Thahash, and Maachah.'); +INSERT INTO t1(docid,words) VALUES(1023001,'And Sarah was an hundred and seven and twenty years old: these were the years of the life of Sarah.'); +INSERT INTO t1(docid,words) VALUES(1023002,'And Sarah died in Kirjatharba; the same is Hebron in the land of Canaan: and Abraham came to mourn for Sarah, and to weep for her.'); +INSERT INTO t1(docid,words) VALUES(1023003,'And Abraham stood up from before his dead, and spake unto the sons of Heth, saying,'); +INSERT INTO t1(docid,words) VALUES(1023004,'I am a stranger and a sojourner with you: give me a possession of a buryingplace with you, that I may bury my dead out of my sight.'); +INSERT INTO t1(docid,words) VALUES(1023005,'And the children of Heth answered Abraham, saying unto him,'); +INSERT INTO t1(docid,words) VALUES(1023006,'Hear us, my lord: thou art a mighty prince among us: in the choice of our sepulchres bury thy dead; none of us shall withhold from thee his sepulchre, but that thou mayest bury thy dead.'); +INSERT INTO t1(docid,words) VALUES(1023007,'And Abraham stood up, and bowed himself to the people of the land, even to the children of Heth.'); +INSERT INTO t1(docid,words) VALUES(1023008,'And he communed with them, saying, If it be your mind that I should bury my dead out of my sight; hear me, and intreat for me to Ephron the son of Zohar,'); +INSERT INTO t1(docid,words) VALUES(1023009,'That he may give me the cave of Machpelah, which he hath, which is in the end of his field; for as much money as it is worth he shall give it me for a possession of a buryingplace amongst you.'); +INSERT INTO t1(docid,words) VALUES(1023010,'And Ephron dwelt among the children of Heth: and Ephron the Hittite answered Abraham in the audience of the children of Heth, even of all that went in at the gate of his city, saying,'); +INSERT INTO t1(docid,words) VALUES(1023011,'Nay, my lord, hear me: the field give I thee, and the cave that is therein, I give it thee; in the presence of the sons of my people give I it thee: bury thy dead.'); +INSERT INTO t1(docid,words) VALUES(1023012,'And Abraham bowed down himself before the people of the land.'); +INSERT INTO t1(docid,words) VALUES(1023013,'And he spake unto Ephron in the audience of the people of the land, saying, But if thou wilt give it, I pray thee, hear me: I will give thee money for the field; take it of me, and I will bury my dead there.'); +INSERT INTO t1(docid,words) VALUES(1023014,'And Ephron answered Abraham, saying unto him,'); +INSERT INTO t1(docid,words) VALUES(1023015,'My lord, hearken unto me: the land is worth four hundred shekels of silver; what is that betwixt me and thee? bury therefore thy dead.'); +INSERT INTO t1(docid,words) VALUES(1023016,'And Abraham hearkened unto Ephron; and Abraham weighed to Ephron the silver, which he had named in the audience of the sons of Heth, four hundred shekels of silver, current money with the merchant.'); +INSERT INTO t1(docid,words) VALUES(1023017,'And the field of Ephron which was in Machpelah, which was before Mamre, the field, and the cave which was therein, and all the trees that were in the field, that were in all the borders round about, were made sure'); +INSERT INTO t1(docid,words) VALUES(1023018,'Unto Abraham for a possession in the presence of the children of Heth, before all that went in at the gate of his city.'); +INSERT INTO t1(docid,words) VALUES(1023019,'And after this, Abraham buried Sarah his wife in the cave of the field of Machpelah before Mamre: the same is Hebron in the land of Canaan.'); +INSERT INTO t1(docid,words) VALUES(1023020,'And the field, and the cave that is therein, were made sure unto Abraham for a possession of a buryingplace by the sons of Heth.'); +INSERT INTO t1(docid,words) VALUES(1024001,'And Abraham was old, and well stricken in age: and the LORD had blessed Abraham in all things.'); +INSERT INTO t1(docid,words) VALUES(1024002,'And Abraham said unto his eldest servant of his house, that ruled over all that he had, Put, I pray thee, thy hand under my thigh:'); +INSERT INTO t1(docid,words) VALUES(1024003,'And I will make thee swear by the LORD, the God of heaven, and the God of the earth, that thou shalt not take a wife unto my son of the daughters of the Canaanites, among whom I dwell:'); +INSERT INTO t1(docid,words) VALUES(1024004,'But thou shalt go unto my country, and to my kindred, and take a wife unto my son Isaac.'); +INSERT INTO t1(docid,words) VALUES(1024005,'And the servant said unto him, Peradventure the woman will not be willing to follow me unto this land: must I needs bring thy son again unto the land from whence thou camest?'); +INSERT INTO t1(docid,words) VALUES(1024006,'And Abraham said unto him, Beware thou that thou bring not my son thither again.'); +INSERT INTO t1(docid,words) VALUES(1024007,'The LORD God of heaven, which took me from my father''s house, and from the land of my kindred, and which spake unto me, and that sware unto me, saying, Unto thy seed will I give this land; he shall send his angel before thee, and thou shalt take a wife unto my son from thence.'); +INSERT INTO t1(docid,words) VALUES(1024008,'And if the woman will not be willing to follow thee, then thou shalt be clear from this my oath: only bring not my son thither again.'); +INSERT INTO t1(docid,words) VALUES(1024009,'And the servant put his hand under the thigh of Abraham his master, and sware to him concerning that matter.'); +INSERT INTO t1(docid,words) VALUES(1024010,'And the servant took ten camels of the camels of his master, and departed; for all the goods of his master were in his hand: and he arose, and went to Mesopotamia, unto the city of Nahor.'); +INSERT INTO t1(docid,words) VALUES(1024011,'And he made his camels to kneel down without the city by a well of water at the time of the evening, even the time that women go out to draw water.'); +INSERT INTO t1(docid,words) VALUES(1024012,'And he said O LORD God of my master Abraham, I pray thee, send me good speed this day, and shew kindness unto my master Abraham.'); +INSERT INTO t1(docid,words) VALUES(1024013,'Behold, I stand here by the well of water; and the daughters of the men of the city come out to draw water:'); +INSERT INTO t1(docid,words) VALUES(1024014,'And let it come to pass, that the damsel to whom I shall say, Let down thy pitcher, I pray thee, that I may drink; and she shall say, Drink, and I will give thy camels drink also: let the same be she that thou hast appointed for thy servant Isaac; and thereby shall I know that thou hast shewed kindness unto my master.'); +INSERT INTO t1(docid,words) VALUES(1024015,'And it came to pass, before he had done speaking, that, behold, Rebekah came out, who was born to Bethuel, son of Milcah, the wife of Nahor, Abraham''s brother, with her pitcher upon her shoulder.'); +INSERT INTO t1(docid,words) VALUES(1024016,'And the damsel was very fair to look upon, a virgin, neither had any man known her: and she went down to the well, and filled her pitcher, and came up.'); +INSERT INTO t1(docid,words) VALUES(1024017,'And the servant ran to meet her, and said, Let me, I pray thee, drink a little water of thy pitcher.'); +INSERT INTO t1(docid,words) VALUES(1024018,'And she said, Drink, my lord: and she hasted, and let down her pitcher upon her hand, and gave him drink.'); +INSERT INTO t1(docid,words) VALUES(1024019,'And when she had done giving him drink, she said, I will draw water for thy camels also, until they have done drinking.'); +INSERT INTO t1(docid,words) VALUES(1024020,'And she hasted, and emptied her pitcher into the trough, and ran again unto the well to draw water, and drew for all his camels.'); +INSERT INTO t1(docid,words) VALUES(1024021,'And the man wondering at her held his peace, to wit whether the LORD had made his journey prosperous or not.'); +INSERT INTO t1(docid,words) VALUES(1024022,'And it came to pass, as the camels had done drinking, that the man took a golden earring of half a shekel weight, and two bracelets for her hands of ten shekels weight of gold;'); +INSERT INTO t1(docid,words) VALUES(1024023,'And said, Whose daughter art thou? tell me, I pray thee: is there room in thy father''s house for us to lodge in?'); +INSERT INTO t1(docid,words) VALUES(1024024,'And she said unto him, I am the daughter of Bethuel the son of Milcah, which she bare unto Nahor.'); +INSERT INTO t1(docid,words) VALUES(1024025,'She said moreover unto him, We have both straw and provender enough, and room to lodge in.'); +INSERT INTO t1(docid,words) VALUES(1024026,'And the man bowed down his head, and worshipped the LORD.'); +INSERT INTO t1(docid,words) VALUES(1024027,'And he said, Blessed be the LORD God of my master Abraham, who hath not left destitute my master of his mercy and his truth: I being in the way, the LORD led me to the house of my master''s brethren.'); +INSERT INTO t1(docid,words) VALUES(1024028,'And the damsel ran, and told them of her mother''s house these things.'); +INSERT INTO t1(docid,words) VALUES(1024029,'And Rebekah had a brother, and his name was Laban: and Laban ran out unto the man, unto the well.'); +INSERT INTO t1(docid,words) VALUES(1024030,'And it came to pass, when he saw the earring and bracelets upon his sister''s hands, and when he heard the words of Rebekah his sister, saying, Thus spake the man unto me; that he came unto the man; and, behold, he stood by the camels at the well.'); +INSERT INTO t1(docid,words) VALUES(1024031,'And he said, Come in, thou blessed of the LORD; wherefore standest thou without? for I have prepared the house, and room for the camels.'); +INSERT INTO t1(docid,words) VALUES(1024032,'And the man came into the house: and he ungirded his camels, and gave straw and provender for the camels, and water to wash his feet, and the men''s feet that were with him.'); +INSERT INTO t1(docid,words) VALUES(1024033,'And there was set meat before him to eat: but he said, I will not eat, until I have told mine errand. And he said, Speak on.'); +INSERT INTO t1(docid,words) VALUES(1024034,'And he said, I am Abraham''s servant.'); +INSERT INTO t1(docid,words) VALUES(1024035,'And the LORD hath blessed my master greatly; and he is become great: and he hath given him flocks, and herds, and silver, and gold, and menservants, and maidservants, and camels, and asses.'); +INSERT INTO t1(docid,words) VALUES(1024036,'And Sarah my master''s wife bare a son to my master when she was old: and unto him hath he given all that he hath.'); +INSERT INTO t1(docid,words) VALUES(1024037,'And my master made me swear, saying, Thou shalt not take a wife to my son of the daughters of the Canaanites, in whose land I dwell:'); +INSERT INTO t1(docid,words) VALUES(1024038,'But thou shalt go unto my father''s house, and to my kindred, and take a wife unto my son.'); +INSERT INTO t1(docid,words) VALUES(1024039,'And I said unto my master, Peradventure the woman will not follow me.'); +INSERT INTO t1(docid,words) VALUES(1024040,'And he said unto me, The LORD, before whom I walk, will send his angel with thee, and prosper thy way; and thou shalt take a wife for my son of my kindred, and of my father''s house:'); +INSERT INTO t1(docid,words) VALUES(1024041,'Then shalt thou be clear from this my oath, when thou comest to my kindred; and if they give not thee one, thou shalt be clear from my oath.'); +INSERT INTO t1(docid,words) VALUES(1024042,'And I came this day unto the well, and said, O LORD God of my master Abraham, if now thou do prosper my way which I go:'); +INSERT INTO t1(docid,words) VALUES(1024043,'Behold, I stand by the well of water; and it shall come to pass, that when the virgin cometh forth to draw water, and I say to her, Give me, I pray thee, a little water of thy pitcher to drink;'); +INSERT INTO t1(docid,words) VALUES(1024044,'And she say to me, Both drink thou, and I will also draw for thy camels: let the same be the woman whom the LORD hath appointed out for my master''s son.'); +INSERT INTO t1(docid,words) VALUES(1024045,'And before I had done speaking in mine heart, behold, Rebekah came forth with her pitcher on her shoulder; and she went down unto the well, and drew water: and I said unto her, Let me drink, I pray thee.'); +INSERT INTO t1(docid,words) VALUES(1024046,'And she made haste, and let down her pitcher from her shoulder, and said, Drink, and I will give thy camels drink also: so I drank, and she made the camels drink also.'); +INSERT INTO t1(docid,words) VALUES(1024047,'And I asked her, and said, Whose daughter art thou? And she said, the daughter of Bethuel, Nahor''s son, whom Milcah bare unto him: and I put the earring upon her face, and the bracelets upon her hands.'); +INSERT INTO t1(docid,words) VALUES(1024048,'And I bowed down my head, and worshipped the LORD, and blessed the LORD God of my master Abraham, which had led me in the right way to take my master''s brother''s daughter unto his son.'); +INSERT INTO t1(docid,words) VALUES(1024049,'And now if ye will deal kindly and truly with my master, tell me: and if not, tell me; that I may turn to the right hand, or to the left.'); +INSERT INTO t1(docid,words) VALUES(1024050,'Then Laban and Bethuel answered and said, The thing proceedeth from the LORD: we cannot speak unto thee bad or good.'); +INSERT INTO t1(docid,words) VALUES(1024051,'Behold, Rebekah is before thee, take her, and go, and let her be thy master''s son''s wife, as the LORD hath spoken.'); +INSERT INTO t1(docid,words) VALUES(1024052,'And it came to pass, that, when Abraham''s servant heard their words, he worshipped the LORD, bowing himself to the earth.'); +INSERT INTO t1(docid,words) VALUES(1024053,'And the servant brought forth jewels of silver, and jewels of gold, and raiment, and gave them to Rebekah: he gave also to her brother and to her mother precious things.'); +INSERT INTO t1(docid,words) VALUES(1024054,'And they did eat and drink, he and the men that were with him, and tarried all night; and they rose up in the morning, and he said, Send me away unto my master.'); +INSERT INTO t1(docid,words) VALUES(1024055,'And her brother and her mother said, Let the damsel abide with us a few days, at the least ten; after that she shall go.'); +INSERT INTO t1(docid,words) VALUES(1024056,'And he said unto them, Hinder me not, seeing the LORD hath prospered my way; send me away that I may go to my master.'); +INSERT INTO t1(docid,words) VALUES(1024057,'And they said, We will call the damsel, and enquire at her mouth.'); +INSERT INTO t1(docid,words) VALUES(1024058,'And they called Rebekah, and said unto her, Wilt thou go with this man? And she said, I will go.'); +INSERT INTO t1(docid,words) VALUES(1024059,'And they sent away Rebekah their sister, and her nurse, and Abraham''s servant, and his men.'); +INSERT INTO t1(docid,words) VALUES(1024060,'And they blessed Rebekah, and said unto her, Thou art our sister, be thou the mother of thousands of millions, and let thy seed possess the gate of those which hate them.'); +INSERT INTO t1(docid,words) VALUES(1024061,'And Rebekah arose, and her damsels, and they rode upon the camels, and followed the man: and the servant took Rebekah, and went his way.'); +INSERT INTO t1(docid,words) VALUES(1024062,'And Isaac came from the way of the well Lahairoi; for he dwelt in the south country.'); +INSERT INTO t1(docid,words) VALUES(1024063,'And Isaac went out to meditate in the field at the eventide: and he lifted up his eyes, and saw, and, behold, the camels were coming.'); +INSERT INTO t1(docid,words) VALUES(1024064,'And Rebekah lifted up her eyes, and when she saw Isaac, she lighted off the camel.'); +INSERT INTO t1(docid,words) VALUES(1024065,'For she had said unto the servant, What man is this that walketh in the field to meet us? And the servant had said, It is my master: therefore she took a vail, and covered herself.'); +INSERT INTO t1(docid,words) VALUES(1024066,'And the servant told Isaac all things that he had done.'); +INSERT INTO t1(docid,words) VALUES(1024067,'And Isaac brought her into his mother Sarah''s tent, and took Rebekah, and she became his wife; and he loved her: and Isaac was comforted after his mother''s death.'); +INSERT INTO t1(docid,words) VALUES(1025001,'Then again Abraham took a wife, and her name was Keturah.'); +INSERT INTO t1(docid,words) VALUES(1025002,'And she bare him Zimran, and Jokshan, and Medan, and Midian, and Ishbak, and Shuah.'); +INSERT INTO t1(docid,words) VALUES(1025003,'And Jokshan begat Sheba, and Dedan. And the sons of Dedan were Asshurim, and Letushim, and Leummim.'); +INSERT INTO t1(docid,words) VALUES(1025004,'And the sons of Midian; Ephah, and Epher, and Hanoch, and Abidah, and Eldaah. All these were the children of Keturah.'); +INSERT INTO t1(docid,words) VALUES(1025005,'And Abraham gave all that he had unto Isaac.'); +INSERT INTO t1(docid,words) VALUES(1025006,'But unto the sons of the concubines, which Abraham had, Abraham gave gifts, and sent them away from Isaac his son, while he yet lived, eastward, unto the east country.'); +INSERT INTO t1(docid,words) VALUES(1025007,'And these are the days of the years of Abraham''s life which he lived, an hundred threescore and fifteen years.'); +INSERT INTO t1(docid,words) VALUES(1025008,'Then Abraham gave up the ghost, and died in a good old age, an old man, and full of years; and was gathered to his people.'); +INSERT INTO t1(docid,words) VALUES(1025009,'And his sons Isaac and Ishmael buried him in the cave of Machpelah, in the field of Ephron the son of Zohar the Hittite, which is before Mamre;'); +INSERT INTO t1(docid,words) VALUES(1025010,'The field which Abraham purchased of the sons of Heth: there was Abraham buried, and Sarah his wife.'); +INSERT INTO t1(docid,words) VALUES(1025011,'And it came to pass after the death of Abraham, that God blessed his son Isaac; and Isaac dwelt by the well Lahairoi.'); +INSERT INTO t1(docid,words) VALUES(1025012,'Now these are the generations of Ishmael, Abraham''s son, whom Hagar the Egyptian, Sarah''s handmaid, bare unto Abraham:'); +INSERT INTO t1(docid,words) VALUES(1025013,'And these are the names of the sons of Ishmael, by their names, according to their generations: the firstborn of Ishmael, Nebajoth; and Kedar, and Adbeel, and Mibsam,'); +INSERT INTO t1(docid,words) VALUES(1025014,'And Mishma, and Dumah, and Massa,'); +INSERT INTO t1(docid,words) VALUES(1025015,'Hadar, and Tema, Jetur, Naphish, and Kedemah:'); +INSERT INTO t1(docid,words) VALUES(1025016,'These are the sons of Ishmael, and these are their names, by their towns, and by their castles; twelve princes according to their nations.'); +INSERT INTO t1(docid,words) VALUES(1025017,'And these are the years of the life of Ishmael, an hundred and thirty and seven years: and he gave up the ghost and died; and was gathered unto his people.'); +INSERT INTO t1(docid,words) VALUES(1025018,'And they dwelt from Havilah unto Shur, that is before Egypt, as thou goest toward Assyria: and he died in the presence of all his brethren.'); +INSERT INTO t1(docid,words) VALUES(1025019,'And these are the generations of Isaac, Abraham''s son: Abraham begat Isaac:'); +INSERT INTO t1(docid,words) VALUES(1025020,'And Isaac was forty years old when he took Rebekah to wife, the daughter of Bethuel the Syrian of Padanaram, the sister to Laban the Syrian.'); +INSERT INTO t1(docid,words) VALUES(1025021,'And Isaac intreated the LORD for his wife, because she was barren: and the LORD was intreated of him, and Rebekah his wife conceived.'); +INSERT INTO t1(docid,words) VALUES(1025022,'And the children struggled together within her; and she said, If it be so, why am I thus? And she went to enquire of the LORD.'); +INSERT INTO t1(docid,words) VALUES(1025023,'And the LORD said unto her, Two nations are in thy womb, and two manner of people shall be separated from thy bowels; and the one people shall be stronger than the other people; and the elder shall serve the younger.'); +INSERT INTO t1(docid,words) VALUES(1025024,'And when her days to be delivered were fulfilled, behold, there were twins in her womb.'); +INSERT INTO t1(docid,words) VALUES(1025025,'And the first came out red, all over like an hairy garment; and they called his name Esau.'); +INSERT INTO t1(docid,words) VALUES(1025026,'And after that came his brother out, and his hand took hold on Esau''s heel; and his name was called Jacob: and Isaac was threescore years old when she bare them.'); +INSERT INTO t1(docid,words) VALUES(1025027,'And the boys grew: and Esau was a cunning hunter, a man of the field; and Jacob was a plain man, dwelling in tents.'); +INSERT INTO t1(docid,words) VALUES(1025028,'And Isaac loved Esau, because he did eat of his venison: but Rebekah loved Jacob.'); +INSERT INTO t1(docid,words) VALUES(1025029,'And Jacob sod pottage: and Esau came from the field, and he was faint:'); +INSERT INTO t1(docid,words) VALUES(1025030,'And Esau said to Jacob, Feed me, I pray thee, with that same red pottage; for I am faint: therefore was his name called Edom.'); +INSERT INTO t1(docid,words) VALUES(1025031,'And Jacob said, Sell me this day thy birthright.'); +INSERT INTO t1(docid,words) VALUES(1025032,'And Esau said, Behold, I am at the point to die: and what profit shall this birthright do to me?'); +INSERT INTO t1(docid,words) VALUES(1025033,'And Jacob said, Swear to me this day; and he sware unto him: and he sold his birthright unto Jacob.'); +INSERT INTO t1(docid,words) VALUES(1025034,'Then Jacob gave Esau bread and pottage of lentiles; and he did eat and drink, and rose up, and went his way: thus Esau despised his birthright.'); +INSERT INTO t1(docid,words) VALUES(1026001,'And there was a famine in the land, beside the first famine that was in the days of Abraham. And Isaac went unto Abimelech king of the Philistines unto Gerar.'); +INSERT INTO t1(docid,words) VALUES(1026002,'And the LORD appeared unto him, and said, Go not down into Egypt; dwell in the land which I shall tell thee of:'); +INSERT INTO t1(docid,words) VALUES(1026003,'Sojourn in this land, and I will be with thee, and will bless thee; for unto thee, and unto thy seed, I will give all these countries, and I will perform the oath which I sware unto Abraham thy father;'); +INSERT INTO t1(docid,words) VALUES(1026004,'And I will make thy seed to multiply as the stars of heaven, and will give unto thy seed all these countries; and in thy seed shall all the nations of the earth be blessed;'); +INSERT INTO t1(docid,words) VALUES(1026005,'Because that Abraham obeyed my voice, and kept my charge, my commandments, my statutes, and my laws.'); +INSERT INTO t1(docid,words) VALUES(1026006,'And Isaac dwelt in Gerar:'); +INSERT INTO t1(docid,words) VALUES(1026007,'And the men of the place asked him of his wife; and he said, She is my sister: for he feared to say, She is my wife; lest, said he, the men of the place should kill me for Rebekah; because she was fair to look upon.'); +INSERT INTO t1(docid,words) VALUES(1026008,'And it came to pass, when he had been there a long time, that Abimelech king of the Philistines looked out at a window, and saw, and, behold, Isaac was sporting with Rebekah his wife.'); +INSERT INTO t1(docid,words) VALUES(1026009,'And Abimelech called Isaac, and said, Behold, of a surety she is thy wife; and how saidst thou, She is my sister? And Isaac said unto him, Because I said, Lest I die for her.'); +INSERT INTO t1(docid,words) VALUES(1026010,'And Abimelech said, What is this thou hast done unto us? one of the people might lightly have lien with thy wife, and thou shouldest have brought guiltiness upon us.'); +INSERT INTO t1(docid,words) VALUES(1026011,'And Abimelech charged all his people, saying, He that toucheth this man or his wife shall surely be put to death.'); +INSERT INTO t1(docid,words) VALUES(1026012,'Then Isaac sowed in that land, and received in the same year an hundredfold: and the LORD blessed him.'); +INSERT INTO t1(docid,words) VALUES(1026013,'And the man waxed great, and went forward, and grew until he became very great:'); +INSERT INTO t1(docid,words) VALUES(1026014,'For he had possession of flocks, and possession of herds, and great store of servants: and the Philistines envied him.'); +INSERT INTO t1(docid,words) VALUES(1026015,'For all the wells which his father''s servants had digged in the days of Abraham his father, the Philistines had stopped them, and filled them with earth.'); +INSERT INTO t1(docid,words) VALUES(1026016,'And Abimelech said unto Isaac, Go from us; for thou art much mightier than we.'); +INSERT INTO t1(docid,words) VALUES(1026017,'And Isaac departed thence, and pitched his tent in the valley of Gerar, and dwelt there.'); +INSERT INTO t1(docid,words) VALUES(1026018,'And Isaac digged again the wells of water, which they had digged in the days of Abraham his father; for the Philistines had stopped them after the death of Abraham: and he called their names after the names by which his father had called them.'); +INSERT INTO t1(docid,words) VALUES(1026019,'And Isaac''s servants digged in the valley, and found there a well of springing water.'); +INSERT INTO t1(docid,words) VALUES(1026020,'And the herdmen of Gerar did strive with Isaac''s herdmen, saying, The water is ours: and he called the name of the well Esek; because they strove with him.'); +INSERT INTO t1(docid,words) VALUES(1026021,'And they digged another well, and strove for that also: and he called the name of it Sitnah.'); +INSERT INTO t1(docid,words) VALUES(1026022,'And he removed from thence, and digged another well; and for that they strove not: and he called the name of it Rehoboth; and he said, For now the LORD hath made room for us, and we shall be fruitful in the land.'); +INSERT INTO t1(docid,words) VALUES(1026023,'And he went up from thence to Beersheba.'); +INSERT INTO t1(docid,words) VALUES(1026024,'And the LORD appeared unto him the same night, and said, I am the God of Abraham thy father: fear not, for I am with thee, and will bless thee, and multiply thy seed for my servant Abraham''s sake.'); +INSERT INTO t1(docid,words) VALUES(1026025,'And he builded an altar there, and called upon the name of the LORD, and pitched his tent there: and there Isaac''s servants digged a well.'); +INSERT INTO t1(docid,words) VALUES(1026026,'Then Abimelech went to him from Gerar, and Ahuzzath one of his friends, and Phichol the chief captain of his army.'); +INSERT INTO t1(docid,words) VALUES(1026027,'And Isaac said unto them, Wherefore come ye to me, seeing ye hate me, and have sent me away from you?'); +INSERT INTO t1(docid,words) VALUES(1026028,'And they said, We saw certainly that the LORD was with thee: and we said, Let there be now an oath betwixt us, even betwixt us and thee, and let us make a covenant with thee;'); +INSERT INTO t1(docid,words) VALUES(1026029,'That thou wilt do us no hurt, as we have not touched thee, and as we have done unto thee nothing but good, and have sent thee away in peace: thou art now the blessed of the LORD.'); +INSERT INTO t1(docid,words) VALUES(1026030,'And he made them a feast, and they did eat and drink.'); +INSERT INTO t1(docid,words) VALUES(1026031,'And they rose up betimes in the morning, and sware one to another: and Isaac sent them away, and they departed from him in peace.'); +INSERT INTO t1(docid,words) VALUES(1026032,'And it came to pass the same day, that Isaac''s servants came, and told him concerning the well which they had digged, and said unto him, We have found water.'); +INSERT INTO t1(docid,words) VALUES(1026033,'And he called it Shebah: therefore the name of the city is Beersheba unto this day.'); +INSERT INTO t1(docid,words) VALUES(1026034,'And Esau was forty years old when he took to wife Judith the daughter of Beeri the Hittite, and Bashemath the daughter of Elon the Hittite:'); +INSERT INTO t1(docid,words) VALUES(1026035,'Which were a grief of mind unto Isaac and to Rebekah.'); +INSERT INTO t1(docid,words) VALUES(1027001,'And it came to pass, that when Isaac was old, and his eyes were dim, so that he could not see, he called Esau his eldest son, and said unto him, My son: and he said unto him, Behold, here am I.'); +INSERT INTO t1(docid,words) VALUES(1027002,'And he said, Behold now, I am old, I know not the day of my death:'); +INSERT INTO t1(docid,words) VALUES(1027003,'Now therefore take, I pray thee, thy weapons, thy quiver and thy bow, and go out to the field, and take me some venison;'); +INSERT INTO t1(docid,words) VALUES(1027004,'And make me savoury meat, such as I love, and bring it to me, that I may eat; that my soul may bless thee before I die.'); +INSERT INTO t1(docid,words) VALUES(1027005,'And Rebekah heard when Isaac spake to Esau his son. And Esau went to the field to hunt for venison, and to bring it.'); +INSERT INTO t1(docid,words) VALUES(1027006,'And Rebekah spake unto Jacob her son, saying, Behold, I heard thy father speak unto Esau thy brother, saying,'); +INSERT INTO t1(docid,words) VALUES(1027007,'Bring me venison, and make me savoury meat, that I may eat, and bless thee before the LORD before my death.'); +INSERT INTO t1(docid,words) VALUES(1027008,'Now therefore, my son, obey my voice according to that which I command thee.'); +INSERT INTO t1(docid,words) VALUES(1027009,'Go now to the flock, and fetch me from thence two good kids of the goats; and I will make them savoury meat for thy father, such as he loveth:'); +INSERT INTO t1(docid,words) VALUES(1027010,'And thou shalt bring it to thy father, that he may eat, and that he may bless thee before his death.'); +INSERT INTO t1(docid,words) VALUES(1027011,'And Jacob said to Rebekah his mother, Behold, Esau my brother is a hairy man, and I am a smooth man:'); +INSERT INTO t1(docid,words) VALUES(1027012,'My father peradventure will feel me, and I shall seem to him as a deceiver; and I shall bring a curse upon me, and not a blessing.'); +INSERT INTO t1(docid,words) VALUES(1027013,'And his mother said unto him, Upon me be thy curse, my son: only obey my voice, and go fetch me them.'); +INSERT INTO t1(docid,words) VALUES(1027014,'And he went, and fetched, and brought them to his mother: and his mother made savoury meat, such as his father loved.'); +INSERT INTO t1(docid,words) VALUES(1027015,'And Rebekah took goodly raiment of her eldest son Esau, which were with her in the house, and put them upon Jacob her younger son:'); +INSERT INTO t1(docid,words) VALUES(1027016,'And she put the skins of the kids of the goats upon his hands, and upon the smooth of his neck:'); +INSERT INTO t1(docid,words) VALUES(1027017,'And she gave the savoury meat and the bread, which she had prepared, into the hand of her son Jacob.'); +INSERT INTO t1(docid,words) VALUES(1027018,'And he came unto his father, and said, My father: and he said, Here am I; who art thou, my son?'); +INSERT INTO t1(docid,words) VALUES(1027019,'And Jacob said unto his father, I am Esau thy first born; I have done according as thou badest me: arise, I pray thee, sit and eat of my venison, that thy soul may bless me.'); +INSERT INTO t1(docid,words) VALUES(1027020,'And Isaac said unto his son, How is it that thou hast found it so quickly, my son? And he said, Because the LORD thy God brought it to me.'); +INSERT INTO t1(docid,words) VALUES(1027021,'And Isaac said unto Jacob, Come near, I pray thee, that I may feel thee, my son, whether thou be my very son Esau or not.'); +INSERT INTO t1(docid,words) VALUES(1027022,'And Jacob went near unto Isaac his father; and he felt him, and said, The voice is Jacob''s voice, but the hands are the hands of Esau.'); +INSERT INTO t1(docid,words) VALUES(1027023,'And he discerned him not, because his hands were hairy, as his brother Esau''s hands: so he blessed him.'); +INSERT INTO t1(docid,words) VALUES(1027024,'And he said, Art thou my very son Esau? And he said, I am.'); +INSERT INTO t1(docid,words) VALUES(1027025,'And he said, Bring it near to me, and I will eat of my son''s venison, that my soul may bless thee. And he brought it near to him, and he did eat: and he brought him wine and he drank.'); +INSERT INTO t1(docid,words) VALUES(1027026,'And his father Isaac said unto him, Come near now, and kiss me, my son.'); +INSERT INTO t1(docid,words) VALUES(1027027,'And he came near, and kissed him: and he smelled the smell of his raiment, and blessed him, and said, See, the smell of my son is as the smell of a field which the LORD hath blessed:'); +INSERT INTO t1(docid,words) VALUES(1027028,'Therefore God give thee of the dew of heaven, and the fatness of the earth, and plenty of corn and wine:'); +INSERT INTO t1(docid,words) VALUES(1027029,'Let people serve thee, and nations bow down to thee: be lord over thy brethren, and let thy mother''s sons bow down to thee: cursed be every one that curseth thee, and blessed be he that blesseth thee.'); +INSERT INTO t1(docid,words) VALUES(1027030,'And it came to pass, as soon as Isaac had made an end of blessing Jacob, and Jacob was yet scarce gone out from the presence of Isaac his father, that Esau his brother came in from his hunting.'); +INSERT INTO t1(docid,words) VALUES(1027031,'And he also had made savoury meat, and brought it unto his father, and said unto his father, Let my father arise, and eat of his son''s venison, that thy soul may bless me.'); +INSERT INTO t1(docid,words) VALUES(1027032,'And Isaac his father said unto him, Who art thou? And he said, I am thy son, thy firstborn Esau.'); +INSERT INTO t1(docid,words) VALUES(1027033,'And Isaac trembled very exceedingly, and said, Who? where is he that hath taken venison, and brought it me, and I have eaten of all before thou camest, and have blessed him? yea, and he shall be blessed.'); +INSERT INTO t1(docid,words) VALUES(1027034,'And when Esau heard the words of his father, he cried with a great and exceeding bitter cry, and said unto his father, Bless me, even me also, O my father.'); +INSERT INTO t1(docid,words) VALUES(1027035,'And he said, Thy brother came with subtilty, and hath taken away thy blessing.'); +INSERT INTO t1(docid,words) VALUES(1027036,'And he said, Is not he rightly named Jacob? for he hath supplanted me these two times: he took away my birthright; and, behold, now he hath taken away my blessing. And he said, Hast thou not reserved a blessing for me?'); +INSERT INTO t1(docid,words) VALUES(1027037,'And Isaac answered and said unto Esau, Behold, I have made him thy lord, and all his brethren have I given to him for servants; and with corn and wine have I sustained him: and what shall I do now unto thee, my son?'); +INSERT INTO t1(docid,words) VALUES(1027038,'And Esau said unto his father, Hast thou but one blessing, my father? bless me, even me also, O my father. And Esau lifted up his voice, and wept.'); +INSERT INTO t1(docid,words) VALUES(1027039,'And Isaac his father answered and said unto him, Behold, thy dwelling shall be the fatness of the earth, and of the dew of heaven from above;'); +INSERT INTO t1(docid,words) VALUES(1027040,'And by thy sword shalt thou live, and shalt serve thy brother; and it shall come to pass when thou shalt have the dominion, that thou shalt break his yoke from off thy neck.'); +INSERT INTO t1(docid,words) VALUES(1027041,'And Esau hated Jacob because of the blessing wherewith his father blessed him: and Esau said in his heart, The days of mourning for my father are at hand; then will I slay my brother Jacob.'); +INSERT INTO t1(docid,words) VALUES(1027042,'And these words of Esau her elder son were told to Rebekah: and she sent and called Jacob her younger son, and said unto him, Behold, thy brother Esau, as touching thee, doth comfort himself, purposing to kill thee.'); +INSERT INTO t1(docid,words) VALUES(1027043,'Now therefore, my son, obey my voice; arise, flee thou to Laban my brother to Haran;'); +INSERT INTO t1(docid,words) VALUES(1027044,'And tarry with him a few days, until thy brother''s fury turn away;'); +INSERT INTO t1(docid,words) VALUES(1027045,'Until thy brother''s anger turn away from thee, and he forget that which thou hast done to him: then I will send, and fetch thee from thence: why should I be deprived also of you both in one day?'); +INSERT INTO t1(docid,words) VALUES(1027046,'And Rebekah said to Isaac, I am weary of my life because of the daughters of Heth: if Jacob take a wife of the daughters of Heth, such as these which are of the daughters of the land, what good shall my life do me?'); +INSERT INTO t1(docid,words) VALUES(1028001,'And Isaac called Jacob, and blessed him, and charged him, and said unto him, Thou shalt not take a wife of the daughters of Canaan.'); +INSERT INTO t1(docid,words) VALUES(1028002,'Arise, go to Padanaram, to the house of Bethuel thy mother''s father; and take thee a wife from thence of the daughers of Laban thy mother''s brother.'); +INSERT INTO t1(docid,words) VALUES(1028003,'And God Almighty bless thee, and make thee fruitful, and multiply thee, that thou mayest be a multitude of people;'); +INSERT INTO t1(docid,words) VALUES(1028004,'And give thee the blessing of Abraham, to thee, and to thy seed with thee; that thou mayest inherit the land wherein thou art a stranger, which God gave unto Abraham.'); +INSERT INTO t1(docid,words) VALUES(1028005,'And Isaac sent away Jacob: and he went to Padanaram unto Laban, son of Bethuel the Syrian, the brother of Rebekah, Jacob''s and Esau''s mother.'); +INSERT INTO t1(docid,words) VALUES(1028006,'When Esau saw that Isaac had blessed Jacob, and sent him away to Padanaram, to take him a wife from thence; and that as he blessed him he gave him a charge, saying, Thou shalt not take a wife of the daughers of Canaan;'); +INSERT INTO t1(docid,words) VALUES(1028007,'And that Jacob obeyed his father and his mother, and was gone to Padanaram;'); +INSERT INTO t1(docid,words) VALUES(1028008,'And Esau seeing that the daughters of Canaan pleased not Isaac his father;'); +INSERT INTO t1(docid,words) VALUES(1028009,'Then went Esau unto Ishmael, and took unto the wives which he had Mahalath the daughter of Ishmael Abraham''s son, the sister of Nebajoth, to be his wife.'); +INSERT INTO t1(docid,words) VALUES(1028010,'And Jacob went out from Beersheba, and went toward Haran.'); +INSERT INTO t1(docid,words) VALUES(1028011,'And he lighted upon a certain place, and tarried there all night, because the sun was set; and he took of the stones of that place, and put them for his pillows, and lay down in that place to sleep.'); +INSERT INTO t1(docid,words) VALUES(1028012,'And he dreamed, and behold a ladder set up on the earth, and the top of it reached to heaven: and behold the angels of God ascending and descending on it.'); +INSERT INTO t1(docid,words) VALUES(1028013,'And, behold, the LORD stood above it, and said, I am the LORD God of Abraham thy father, and the God of Isaac: the land whereon thou liest, to thee will I give it, and to thy seed;'); +INSERT INTO t1(docid,words) VALUES(1028014,'And thy seed shall be as the dust of the earth, and thou shalt spread abroad to the west, and to the east, and to the north, and to the south: and in thee and in thy seed shall all the families of the earth be blessed.'); +INSERT INTO t1(docid,words) VALUES(1028015,'And, behold, I am with thee, and will keep thee in all places whither thou goest, and will bring thee again into this land; for I will not leave thee, until I have done that which I have spoken to thee of.'); +INSERT INTO t1(docid,words) VALUES(1028016,'And Jacob awaked out of his sleep, and he said, Surely the LORD is in this place; and I knew it not.'); +INSERT INTO t1(docid,words) VALUES(1028017,'And he was afraid, and said, How dreadful is this place! this is none other but the house of God, and this is the gate of heaven.'); +INSERT INTO t1(docid,words) VALUES(1028018,'And Jacob rose up early in the morning, and took the stone that he had put for his pillows, and set it up for a pillar, and poured oil upon the top of it.'); +INSERT INTO t1(docid,words) VALUES(1028019,'And he called the name of that place Bethel: but the name of that city was called Luz at the first.'); +INSERT INTO t1(docid,words) VALUES(1028020,'And Jacob vowed a vow, saying, If God will be with me, and will keep me in this way that I go, and will give me bread to eat, and raiment to put on,'); +INSERT INTO t1(docid,words) VALUES(1028021,'So that I come again to my father''s house in peace; then shall the LORD be my God:'); +INSERT INTO t1(docid,words) VALUES(1028022,'And this stone, which I have set for a pillar, shall be God''s house: and of all that thou shalt give me I will surely give the tenth unto thee.'); +INSERT INTO t1(docid,words) VALUES(1029001,'Then Jacob went on his journey, and came into the land of the people of the east.'); +INSERT INTO t1(docid,words) VALUES(1029002,'And he looked, and behold a well in the field, and, lo, there were three flocks of sheep lying by it; for out of that well they watered the flocks: and a great stone was upon the well''s mouth.'); +INSERT INTO t1(docid,words) VALUES(1029003,'And thither were all the flocks gathered: and they rolled the stone from the well''s mouth, and watered the sheep, and put the stone again upon the well''s mouth in his place.'); +INSERT INTO t1(docid,words) VALUES(1029004,'And Jacob said unto them, My brethren, whence be ye? And they said, Of Haran are we.'); +INSERT INTO t1(docid,words) VALUES(1029005,'And he said unto them, Know ye Laban the son of Nahor? And they said, We know him.'); +INSERT INTO t1(docid,words) VALUES(1029006,'And he said unto them, Is he well? And they said, He is well: and, behold, Rachel his daughter cometh with the sheep.'); +INSERT INTO t1(docid,words) VALUES(1029007,'And he said, Lo, it is yet high day, neither is it time that the cattle should be gathered together: water ye the sheep, and go and feed them.'); +INSERT INTO t1(docid,words) VALUES(1029008,'And they said, We cannot, until all the flocks be gathered together, and till they roll the stone from the well''s mouth; then we water the sheep.'); +INSERT INTO t1(docid,words) VALUES(1029009,'And while he yet spake with them, Rachel came with her father''s sheep; for she kept them.'); +INSERT INTO t1(docid,words) VALUES(1029010,'And it came to pass, when Jacob saw Rachel the daughter of Laban his mother''s brother, and the sheep of Laban his mother''s brother, that Jacob went near, and rolled the stone from the well''s mouth, and watered the flock of Laban his mother''s brother.'); +INSERT INTO t1(docid,words) VALUES(1029011,'And Jacob kissed Rachel, and lifted up his voice, and wept.'); +INSERT INTO t1(docid,words) VALUES(1029012,'And Jacob told Rachel that he was her father''s brother, and that he was Rebekah''s son: and she ran and told her father.'); +INSERT INTO t1(docid,words) VALUES(1029013,'And it came to pass, when Laban heard the tidings of Jacob his sister''s son, that he ran to meet him, and embraced him, and kissed him, and brought him to his house. And he told Laban all these things.'); +INSERT INTO t1(docid,words) VALUES(1029014,'And Laban said to him, Surely thou art my bone and my flesh. And he abode with him the space of a month.'); +INSERT INTO t1(docid,words) VALUES(1029015,'And Laban said unto Jacob, Because thou art my brother, shouldest thou therefore serve me for nought? tell me, what shall thy wages be?'); +INSERT INTO t1(docid,words) VALUES(1029016,'And Laban had two daughters: the name of the elder was Leah, and the name of the younger was Rachel.'); +INSERT INTO t1(docid,words) VALUES(1029017,'Leah was tender eyed; but Rachel was beautiful and well favoured.'); +INSERT INTO t1(docid,words) VALUES(1029018,'And Jacob loved Rachel; and said, I will serve thee seven years for Rachel thy younger daughter.'); +INSERT INTO t1(docid,words) VALUES(1029019,'And Laban said, It is better that I give her to thee, than that I should give her to another man: abide with me.'); +INSERT INTO t1(docid,words) VALUES(1029020,'And Jacob served seven years for Rachel; and they seemed unto him but a few days, for the love he had to her.'); +INSERT INTO t1(docid,words) VALUES(1029021,'And Jacob said unto Laban, Give me my wife, for my days are fulfilled, that I may go in unto her.'); +INSERT INTO t1(docid,words) VALUES(1029022,'And Laban gathered together all the men of the place, and made a feast.'); +INSERT INTO t1(docid,words) VALUES(1029023,'And it came to pass in the evening, that he took Leah his daughter, and brought her to him; and he went in unto her.'); +INSERT INTO t1(docid,words) VALUES(1029024,'And Laban gave unto his daughter Leah Zilpah his maid for an handmaid.'); +INSERT INTO t1(docid,words) VALUES(1029025,'And it came to pass, that in the morning, behold, it was Leah: and he said to Laban, What is this thou hast done unto me? did not I serve with thee for Rachel? wherefore then hast thou beguiled me?'); +INSERT INTO t1(docid,words) VALUES(1029026,'And Laban said, It must not be so done in our country, to give the younger before the firstborn.'); +INSERT INTO t1(docid,words) VALUES(1029027,'Fulfil her week, and we will give thee this also for the service which thou shalt serve with me yet seven other years.'); +INSERT INTO t1(docid,words) VALUES(1029028,'And Jacob did so, and fulfilled her week: and he gave him Rachel his daughter to wife also.'); +INSERT INTO t1(docid,words) VALUES(1029029,'And Laban gave to Rachel his daughter Bilhah his handmaid to be her maid.'); +INSERT INTO t1(docid,words) VALUES(1029030,'And he went in also unto Rachel, and he loved also Rachel more than Leah, and served with him yet seven other years.'); +INSERT INTO t1(docid,words) VALUES(1029031,'And when the LORD saw that Leah was hated, he opened her womb: but Rachel was barren.'); +INSERT INTO t1(docid,words) VALUES(1029032,'And Leah conceived, and bare a son, and she called his name Reuben: for she said, Surely the LORD hath looked upon my affliction; now therefore my husband will love me.'); +INSERT INTO t1(docid,words) VALUES(1029033,'And she conceived again, and bare a son; and said, Because the LORD hath heard I was hated, he hath therefore given me this son also: and she called his name Simeon.'); +INSERT INTO t1(docid,words) VALUES(1029034,'And she conceived again, and bare a son; and said, Now this time will my husband be joined unto me, because I have born him three sons: therefore was his name called Levi.'); +INSERT INTO t1(docid,words) VALUES(1029035,'And she conceived again, and bare a son: and she said, Now will I praise the LORD: therefore she called his name Judah; and left bearing.'); +INSERT INTO t1(docid,words) VALUES(1030001,'And when Rachel saw that she bare Jacob no children, Rachel envied her sister; and said unto Jacob, Give me children, or else I die.'); +INSERT INTO t1(docid,words) VALUES(1030002,'And Jacob''s anger was kindled against Rachel: and he said, Am I in God''s stead, who hath withheld from thee the fruit of the womb?'); +INSERT INTO t1(docid,words) VALUES(1030003,'And she said, Behold my maid Bilhah, go in unto her; and she shall bear upon my knees, that I may also have children by her.'); +INSERT INTO t1(docid,words) VALUES(1030004,'And she gave him Bilhah her handmaid to wife: and Jacob went in unto her.'); +INSERT INTO t1(docid,words) VALUES(1030005,'And Bilhah conceived, and bare Jacob a son.'); +INSERT INTO t1(docid,words) VALUES(1030006,'And Rachel said, God hath judged me, and hath also heard my voice, and hath given me a son: therefore called she his name Dan.'); +INSERT INTO t1(docid,words) VALUES(1030007,'And Bilhah Rachel''s maid conceived again, and bare Jacob a second son.'); +INSERT INTO t1(docid,words) VALUES(1030008,'And Rachel said, With great wrestlings have I wrestled with my sister, and I have prevailed: and she called his name Naphtali.'); +INSERT INTO t1(docid,words) VALUES(1030009,'When Leah saw that she had left bearing, she took Zilpah her maid, and gave her Jacob to wife.'); +INSERT INTO t1(docid,words) VALUES(1030010,'And Zilpah Leah''s maid bare Jacob a son.'); +INSERT INTO t1(docid,words) VALUES(1030011,'And Leah said, A troop cometh: and she called his name Gad.'); +INSERT INTO t1(docid,words) VALUES(1030012,'And Zilpah Leah''s maid bare Jacob a second son.'); +INSERT INTO t1(docid,words) VALUES(1030013,'And Leah said, Happy am I, for the daughters will call me blessed: and she called his name Asher.'); +INSERT INTO t1(docid,words) VALUES(1030014,'And Reuben went in the days of wheat harvest, and found mandrakes in the field, and brought them unto his mother Leah. Then Rachel said to Leah, Give me, I pray thee, of thy son''s mandrakes.'); +INSERT INTO t1(docid,words) VALUES(1030015,'And she said unto her, Is it a small matter that thou hast taken my husband? and wouldest thou take away my son''s mandrakes also? And Rachel said, Therefore he shall lie with thee to night for thy son''s mandrakes.'); +INSERT INTO t1(docid,words) VALUES(1030016,'And Jacob came out of the field in the evening, and Leah went out to meet him, and said, Thou must come in unto me; for surely I have hired thee with my son''s mandrakes. And he lay with her that night.'); +INSERT INTO t1(docid,words) VALUES(1030017,'And God hearkened unto Leah, and she conceived, and bare Jacob the fifth son.'); +INSERT INTO t1(docid,words) VALUES(1030018,'And Leah said, God hath given me my hire, because I have given my maiden to my husband: and she called his name Issachar.'); +INSERT INTO t1(docid,words) VALUES(1030019,'And Leah conceived again, and bare Jacob the sixth son.'); +INSERT INTO t1(docid,words) VALUES(1030020,'And Leah said, God hath endued me with a good dowry; now will my husband dwell with me, because I have born him six sons: and she called his name Zebulun.'); +INSERT INTO t1(docid,words) VALUES(1030021,'And afterwards she bare a daughter, and called her name Dinah.'); +INSERT INTO t1(docid,words) VALUES(1030022,'And God remembered Rachel, and God hearkened to her, and opened her womb.'); +INSERT INTO t1(docid,words) VALUES(1030023,'And she conceived, and bare a son; and said, God hath taken away my reproach:'); +INSERT INTO t1(docid,words) VALUES(1030024,'And she called his name Joseph; and said, The LORD shall add to me another son.'); +INSERT INTO t1(docid,words) VALUES(1030025,'And it came to pass, when Rachel had born Joseph, that Jacob said unto Laban, Send me away, that I may go unto mine own place, and to my country.'); +INSERT INTO t1(docid,words) VALUES(1030026,'Give me my wives and my children, for whom I have served thee, and let me go: for thou knowest my service which I have done thee.'); +INSERT INTO t1(docid,words) VALUES(1030027,'And Laban said unto him, I pray thee, if I have found favour in thine eyes, tarry: for I have learned by experience that the LORD hath blessed me for thy sake.'); +INSERT INTO t1(docid,words) VALUES(1030028,'And he said, Appoint me thy wages, and I will give it.'); +INSERT INTO t1(docid,words) VALUES(1030029,'And he said unto him, Thou knowest how I have served thee, and how thy cattle was with me.'); +INSERT INTO t1(docid,words) VALUES(1030030,'For it was little which thou hadst before I came, and it is now increased unto a multitude; and the LORD hath blessed thee since my coming: and now when shall I provide for mine own house also?'); +INSERT INTO t1(docid,words) VALUES(1030031,'And he said, What shall I give thee? And Jacob said, Thou shalt not give me any thing: if thou wilt do this thing for me, I will again feed and keep thy flock.'); +INSERT INTO t1(docid,words) VALUES(1030032,'I will pass through all thy flock to day, removing from thence all the speckled and spotted cattle, and all the brown cattle among the sheep, and the spotted and speckled among the goats: and of such shall be my hire.'); +INSERT INTO t1(docid,words) VALUES(1030033,'So shall my righteousness answer for me in time to come, when it shall come for my hire before thy face: every one that is not speckled and spotted among the goats, and brown among the sheep, that shall be counted stolen with me.'); +INSERT INTO t1(docid,words) VALUES(1030034,'And Laban said, Behold, I would it might be according to thy word.'); +INSERT INTO t1(docid,words) VALUES(1030035,'And he removed that day the he goats that were ringstraked and spotted, and all the she goats that were speckled and spotted, and every one that had some white in it, and all the brown among the sheep, and gave them into the hand of his sons.'); +INSERT INTO t1(docid,words) VALUES(1030036,'And he set three days'' journey betwixt himself and Jacob: and Jacob fed the rest of Laban''s flocks.'); +INSERT INTO t1(docid,words) VALUES(1030037,'And Jacob took him rods of green poplar, and of the hazel and chesnut tree; and pilled white strakes in them, and made the white appear which was in the rods.'); +INSERT INTO t1(docid,words) VALUES(1030038,'And he set the rods which he had pilled before the flocks in the gutters in the watering troughs when the flocks came to drink, that they should conceive when they came to drink.'); +INSERT INTO t1(docid,words) VALUES(1030039,'And the flocks conceived before the rods, and brought forth cattle ringstraked, speckled, and spotted.'); +INSERT INTO t1(docid,words) VALUES(1030040,'And Jacob did separate the lambs, and set the faces of the flocks toward the ringstraked, and all the brown in the flock of Laban; and he put his own flocks by themselves, and put them not unto Laban''s cattle.'); +INSERT INTO t1(docid,words) VALUES(1030041,'And it came to pass, whensoever the stronger cattle did conceive, that Jacob laid the rods before the eyes of the cattle in the gutters, that they might conceive among the rods.'); +INSERT INTO t1(docid,words) VALUES(1030042,'But when the cattle were feeble, he put them not in: so the feebler were Laban''s, and the stronger Jacob''s.'); +INSERT INTO t1(docid,words) VALUES(1030043,'And the man increased exceedingly, and had much cattle, and maidservants, and menservants, and camels, and asses.'); +INSERT INTO t1(docid,words) VALUES(1031001,'And he heard the words of Laban''s sons, saying, Jacob hath taken away all that was our father''s; and of that which was our father''s hath he gotten all this glory.'); +INSERT INTO t1(docid,words) VALUES(1031002,'And Jacob beheld the countenance of Laban, and, behold, it was not toward him as before.'); +INSERT INTO t1(docid,words) VALUES(1031003,'And the LORD said unto Jacob, Return unto the land of thy fathers, and to thy kindred; and I will be with thee.'); +INSERT INTO t1(docid,words) VALUES(1031004,'And Jacob sent and called Rachel and Leah to the field unto his flock,'); +INSERT INTO t1(docid,words) VALUES(1031005,'And said unto them, I see your father''s countenance, that it is not toward me as before; but the God of my father hath been with me.'); +INSERT INTO t1(docid,words) VALUES(1031006,'And ye know that with all my power I have served your father.'); +INSERT INTO t1(docid,words) VALUES(1031007,'And your father hath deceived me, and changed my wages ten times; but God suffered him not to hurt me.'); +INSERT INTO t1(docid,words) VALUES(1031008,'If he said thus, The speckled shall be thy wages; then all the cattle bare speckled: and if he said thus, The ringstraked shall be thy hire; then bare all the cattle ringstraked.'); +INSERT INTO t1(docid,words) VALUES(1031009,'Thus God hath taken away the cattle of your father, and given them to me.'); +INSERT INTO t1(docid,words) VALUES(1031010,'And it came to pass at the time that the cattle conceived, that I lifted up mine eyes, and saw in a dream, and, behold, the rams which leaped upon the cattle were ringstraked, speckled, and grisled.'); +INSERT INTO t1(docid,words) VALUES(1031011,'And the angel of God spake unto me in a dream, saying, Jacob: And I said, Here am I.'); +INSERT INTO t1(docid,words) VALUES(1031012,'And he said, Lift up now thine eyes, and see, all the rams which leap upon the cattle are ringstraked, speckled, and grisled: for I have seen all that Laban doeth unto thee.'); +INSERT INTO t1(docid,words) VALUES(1031013,'I am the God of Bethel, where thou anointedst the pillar, and where thou vowedst a vow unto me: now arise, get thee out from this land, and return unto the land of thy kindred.'); +INSERT INTO t1(docid,words) VALUES(1031014,'And Rachel and Leah answered and said unto him, Is there yet any portion or inheritance for us in our father''s house?'); +INSERT INTO t1(docid,words) VALUES(1031015,'Are we not counted of him strangers? for he hath sold us, and hath quite devoured also our money.'); +INSERT INTO t1(docid,words) VALUES(1031016,'For all the riches which God hath taken from our father, that is ours, and our children''s: now then, whatsoever God hath said unto thee, do.'); +INSERT INTO t1(docid,words) VALUES(1031017,'Then Jacob rose up, and set his sons and his wives upon camels;'); +INSERT INTO t1(docid,words) VALUES(1031018,'And he carried away all his cattle, and all his goods which he had gotten, the cattle of his getting, which he had gotten in Padanaram, for to go to Isaac his father in the land of Canaan.'); +INSERT INTO t1(docid,words) VALUES(1031019,'And Laban went to shear his sheep: and Rachel had stolen the images that were her father''s.'); +INSERT INTO t1(docid,words) VALUES(1031020,'And Jacob stole away unawares to Laban the Syrian, in that he told him not that he fled.'); +INSERT INTO t1(docid,words) VALUES(1031021,'So he fled with all that he had; and he rose up, and passed over the river, and set his face toward the mount Gilead.'); +INSERT INTO t1(docid,words) VALUES(1031022,'And it was told Laban on the third day that Jacob was fled.'); +INSERT INTO t1(docid,words) VALUES(1031023,'And he took his brethren with him, and pursued after him seven days'' journey; and they overtook him in the mount Gilead.'); +INSERT INTO t1(docid,words) VALUES(1031024,'And God came to Laban the Syrian in a dream by night, and said unto him, Take heed that thou speak not to Jacob either good or bad.'); +INSERT INTO t1(docid,words) VALUES(1031025,'Then Laban overtook Jacob. Now Jacob had pitched his tent in the mount: and Laban with his brethren pitched in the mount of Gilead.'); +INSERT INTO t1(docid,words) VALUES(1031026,'And Laban said to Jacob, What hast thou done, that thou hast stolen away unawares to me, and carried away my daughters, as captives taken with the sword?'); +INSERT INTO t1(docid,words) VALUES(1031027,'Wherefore didst thou flee away secretly, and steal away from me; and didst not tell me, that I might have sent thee away with mirth, and with songs, with tabret, and with harp?'); +INSERT INTO t1(docid,words) VALUES(1031028,'And hast not suffered me to kiss my sons and my daughters? thou hast now done foolishly in so doing.'); +INSERT INTO t1(docid,words) VALUES(1031029,'It is in the power of my hand to do you hurt: but the God of your father spake unto me yesternight, saying, Take thou heed that thou speak not to Jacob either good or bad.'); +INSERT INTO t1(docid,words) VALUES(1031030,'And now, though thou wouldest needs be gone, because thou sore longedst after thy father''s house, yet wherefore hast thou stolen my gods?'); +INSERT INTO t1(docid,words) VALUES(1031031,'And Jacob answered and said to Laban, Because I was afraid: for I said, Peradventure thou wouldest take by force thy daughters from me.'); +INSERT INTO t1(docid,words) VALUES(1031032,'With whomsoever thou findest thy gods, let him not live: before our brethren discern thou what is thine with me, and take it to thee. For Jacob knew not that Rachel had stolen them.'); +INSERT INTO t1(docid,words) VALUES(1031033,'And Laban went into Jacob''s tent, and into Leah''s tent, and into the two maidservants'' tents; but he found them not. Then went he out of Leah''s tent, and entered into Rachel''s tent.'); +INSERT INTO t1(docid,words) VALUES(1031034,'Now Rachel had taken the images, and put them in the camel''s furniture, and sat upon them. And Laban searched all the tent, but found them not.'); +INSERT INTO t1(docid,words) VALUES(1031035,'And she said to her father, Let it not displease my lord that I cannot rise up before thee; for the custom of women is upon me. And he searched but found not the images.'); +INSERT INTO t1(docid,words) VALUES(1031036,'And Jacob was wroth, and chode with Laban: and Jacob answered and said to Laban, What is my trespass? what is my sin, that thou hast so hotly pursued after me?'); +INSERT INTO t1(docid,words) VALUES(1031037,'Whereas thou hast searched all my stuff, what hast thou found of all thy household stuff? set it here before my brethren and thy brethren, that they may judge betwixt us both.'); +INSERT INTO t1(docid,words) VALUES(1031038,'This twenty years have I been with thee; thy ewes and thy she goats have not cast their young, and the rams of thy flock have I not eaten.'); +INSERT INTO t1(docid,words) VALUES(1031039,'That which was torn of beasts I brought not unto thee; I bare the loss of it; of my hand didst thou require it, whether stolen by day, or stolen by night.'); +INSERT INTO t1(docid,words) VALUES(1031040,'Thus I was; in the day the drought consumed me, and the frost by night; and my sleep departed from mine eyes.'); +INSERT INTO t1(docid,words) VALUES(1031041,'Thus have I been twenty years in thy house; I served thee fourteen years for thy two daughters, and six years for thy cattle: and thou hast changed my wages ten times.'); +INSERT INTO t1(docid,words) VALUES(1031042,'Except the God of my father, the God of Abraham, and the fear of Isaac, had been with me, surely thou hadst sent me away now empty. God hath seen mine affliction and the labour of my hands, and rebuked thee yesternight.'); +INSERT INTO t1(docid,words) VALUES(1031043,'And Laban answered and said unto Jacob, These daughters are my daughters, and these children are my children, and these cattle are my cattle, and all that thou seest is mine: and what can I do this day unto these my daughters, or unto their children which they have born?'); +INSERT INTO t1(docid,words) VALUES(1031044,'Now therefore come thou, let us make a covenant, I and thou; and let it be for a witness between me and thee.'); +INSERT INTO t1(docid,words) VALUES(1031045,'And Jacob took a stone, and set it up for a pillar.'); +INSERT INTO t1(docid,words) VALUES(1031046,'And Jacob said unto his brethren, Gather stones; and they took stones, and made an heap: and they did eat there upon the heap.'); +INSERT INTO t1(docid,words) VALUES(1031047,'And Laban called it Jegarsahadutha: but Jacob called it Galeed.'); +INSERT INTO t1(docid,words) VALUES(1031048,'And Laban said, This heap is a witness between me and thee this day. Therefore was the name of it called Galeed;'); +INSERT INTO t1(docid,words) VALUES(1031049,'And Mizpah; for he said, The LORD watch between me and thee, when we are absent one from another.'); +INSERT INTO t1(docid,words) VALUES(1031050,'If thou shalt afflict my daughters, or if thou shalt take other wives beside my daughters, no man is with us; see, God is witness betwixt me and thee.'); +INSERT INTO t1(docid,words) VALUES(1031051,'And Laban said to Jacob, Behold this heap, and behold this pillar, which I have cast betwixt me and thee:'); +INSERT INTO t1(docid,words) VALUES(1031052,'This heap be witness, and this pillar be witness, that I will not pass over this heap to thee, and that thou shalt not pass over this heap and this pillar unto me, for harm.'); +INSERT INTO t1(docid,words) VALUES(1031053,'The God of Abraham, and the God of Nahor, the God of their father, judge betwixt us. And Jacob sware by the fear of his father Isaac.'); +INSERT INTO t1(docid,words) VALUES(1031054,'Then Jacob offered sacrifice upon the mount, and called his brethren to eat bread: and they did eat bread, and tarried all night in the mount.'); +INSERT INTO t1(docid,words) VALUES(1031055,'And early in the morning Laban rose up, and kissed his sons and his daughters, and blessed them: and Laban departed, and returned unto his place.'); +INSERT INTO t1(docid,words) VALUES(1032001,'And Jacob went on his way, and the angels of God met him.'); +INSERT INTO t1(docid,words) VALUES(1032002,'And when Jacob saw them, he said, This is God''s host: and he called the name of that place Mahanaim.'); +INSERT INTO t1(docid,words) VALUES(1032003,'And Jacob sent messengers before him to Esau his brother unto the land of Seir, the country of Edom.'); +INSERT INTO t1(docid,words) VALUES(1032004,'And he commanded them, saying, Thus shall ye speak unto my lord Esau; Thy servant Jacob saith thus, I have sojourned with Laban, and stayed there until now:'); +INSERT INTO t1(docid,words) VALUES(1032005,'And I have oxen, and asses, flocks, and menservants, and womenservants: and I have sent to tell my lord, that I may find grace in thy sight.'); +INSERT INTO t1(docid,words) VALUES(1032006,'And the messengers returned to Jacob, saying, We came to thy brother Esau, and also he cometh to meet thee, and four hundred men with him.'); +INSERT INTO t1(docid,words) VALUES(1032007,'Then Jacob was greatly afraid and distressed: and he divided the people that was with him, and the flocks, and herds, and the camels, into two bands;'); +INSERT INTO t1(docid,words) VALUES(1032008,'And said, If Esau come to the one company, and smite it, then the other company which is left shall escape.'); +INSERT INTO t1(docid,words) VALUES(1032009,'And Jacob said, O God of my father Abraham, and God of my father Isaac, the LORD which saidst unto me, Return unto thy country, and to thy kindred, and I will deal well with thee:'); +INSERT INTO t1(docid,words) VALUES(1032010,'I am not worthy of the least of all the mercies, and of all the truth, which thou hast shewed unto thy servant; for with my staff I passed over this Jordan; and now I am become two bands.'); +INSERT INTO t1(docid,words) VALUES(1032011,'Deliver me, I pray thee, from the hand of my brother, from the hand of Esau: for I fear him, lest he will come and smite me, and the mother with the children.'); +INSERT INTO t1(docid,words) VALUES(1032012,'And thou saidst, I will surely do thee good, and make thy seed as the sand of the sea, which cannot be numbered for multitude.'); +INSERT INTO t1(docid,words) VALUES(1032013,'And he lodged there that same night; and took of that which came to his hand a present for Esau his brother;'); +INSERT INTO t1(docid,words) VALUES(1032014,'Two hundred she goats, and twenty he goats, two hundred ewes, and twenty rams,'); +INSERT INTO t1(docid,words) VALUES(1032015,'Thirty milch camels with their colts, forty kine, and ten bulls, twenty she asses, and ten foals.'); +INSERT INTO t1(docid,words) VALUES(1032016,'And he delivered them into the hand of his servants, every drove by themselves; and said unto his servants, Pass over before me, and put a space betwixt drove and drove.'); +INSERT INTO t1(docid,words) VALUES(1032017,'And he commanded the foremost, saying, When Esau my brother meeteth thee, and asketh thee, saying, Whose art thou? and whither goest thou? and whose are these before thee?'); +INSERT INTO t1(docid,words) VALUES(1032018,'Then thou shalt say, They be thy servant Jacob''s; it is a present sent unto my lord Esau: and, behold, also he is behind us.'); +INSERT INTO t1(docid,words) VALUES(1032019,'And so commanded he the second, and the third, and all that followed the droves, saying, On this manner shall ye speak unto Esau, when ye find him.'); +INSERT INTO t1(docid,words) VALUES(1032020,'And say ye moreover, Behold, thy servant Jacob is behind us. For he said, I will appease him with the present that goeth before me, and afterward I will see his face; peradventure he will accept of me.'); +INSERT INTO t1(docid,words) VALUES(1032021,'So went the present over before him: and himself lodged that night in the company.'); +INSERT INTO t1(docid,words) VALUES(1032022,'And he rose up that night, and took his two wives, and his two womenservants, and his eleven sons, and passed over the ford Jabbok.'); +INSERT INTO t1(docid,words) VALUES(1032023,'And he took them, and sent them over the brook, and sent over that he had.'); +INSERT INTO t1(docid,words) VALUES(1032024,'And Jacob was left alone; and there wrestled a man with him until the breaking of the day.'); +INSERT INTO t1(docid,words) VALUES(1032025,'And when he saw that he prevailed not against him, he touched the hollow of his thigh; and the hollow of Jacob''s thigh was out of joint, as he wrestled with him.'); +INSERT INTO t1(docid,words) VALUES(1032026,'And he said, Let me go, for the day breaketh. And he said, I will not let thee go, except thou bless me.'); +INSERT INTO t1(docid,words) VALUES(1032027,'And he said unto him, What is thy name? And he said, Jacob.'); +INSERT INTO t1(docid,words) VALUES(1032028,'And he said, Thy name shall be called no more Jacob, but Israel: for as a prince hast thou power with God and with men, and hast prevailed.'); +INSERT INTO t1(docid,words) VALUES(1032029,'And Jacob asked him, and said, Tell me, I pray thee, thy name. And he said, Wherefore is it that thou dost ask after my name? And he blessed him there.'); +INSERT INTO t1(docid,words) VALUES(1032030,'And Jacob called the name of the place Peniel: for I have seen God face to face, and my life is preserved.'); +INSERT INTO t1(docid,words) VALUES(1032031,'And as he passed over Penuel the sun rose upon him, and he halted upon his thigh.'); +INSERT INTO t1(docid,words) VALUES(1032032,'Therefore the children of Israel eat not of the sinew which shrank, which is upon the hollow of the thigh, unto this day: because he touched the hollow of Jacob''s thigh in the sinew that shrank.'); +INSERT INTO t1(docid,words) VALUES(1033001,'And Jacob lifted up his eyes, and looked, and, behold, Esau came, and with him four hundred men. And he divided the children unto Leah, and unto Rachel, and unto the two handmaids.'); +INSERT INTO t1(docid,words) VALUES(1033002,'And he put the handmaids and their children foremost, and Leah and her children after, and Rachel and Joseph hindermost.'); +INSERT INTO t1(docid,words) VALUES(1033003,'And he passed over before them, and bowed himself to the ground seven times, until he came near to his brother.'); +INSERT INTO t1(docid,words) VALUES(1033004,'And Esau ran to meet him, and embraced him, and fell on his neck, and kissed him: and they wept.'); +INSERT INTO t1(docid,words) VALUES(1033005,'And he lifted up his eyes, and saw the women and the children; and said, Who are those with thee? And he said, The children which God hath graciously given thy servant.'); +INSERT INTO t1(docid,words) VALUES(1033006,'Then the handmaidens came near, they and their children, and they bowed themselves.'); +INSERT INTO t1(docid,words) VALUES(1033007,'And Leah also with her children came near, and bowed themselves: and after came Joseph near and Rachel, and they bowed themselves.'); +INSERT INTO t1(docid,words) VALUES(1033008,'And he said, What meanest thou by all this drove which I met? And he said, These are to find grace in the sight of my lord.'); +INSERT INTO t1(docid,words) VALUES(1033009,'And Esau said, I have enough, my brother; keep that thou hast unto thyself.'); +INSERT INTO t1(docid,words) VALUES(1033010,'And Jacob said, Nay, I pray thee, if now I have found grace in thy sight, then receive my present at my hand: for therefore I have seen thy face, as though I had seen the face of God, and thou wast pleased with me.'); +INSERT INTO t1(docid,words) VALUES(1033011,'Take, I pray thee, my blessing that is brought to thee; because God hath dealt graciously with me, and because I have enough. And he urged him, and he took it.'); +INSERT INTO t1(docid,words) VALUES(1033012,'And he said, Let us take our journey, and let us go, and I will go before thee.'); +INSERT INTO t1(docid,words) VALUES(1033013,'And he said unto him, My lord knoweth that the children are tender, and the flocks and herds with young are with me: and if men should overdrive them one day, all the flock will die.'); +INSERT INTO t1(docid,words) VALUES(1033014,'Let my lord, I pray thee, pass over before his servant: and I will lead on softly, according as the cattle that goeth before me and the children be able to endure, until I come unto my lord unto Seir.'); +INSERT INTO t1(docid,words) VALUES(1033015,'And Esau said, Let me now leave with thee some of the folk that are with me. And he said, What needeth it? let me find grace in the sight of my lord.'); +INSERT INTO t1(docid,words) VALUES(1033016,'So Esau returned that day on his way unto Seir.'); +INSERT INTO t1(docid,words) VALUES(1033017,'And Jacob journeyed to Succoth, and built him an house, and made booths for his cattle: therefore the name of the place is called Succoth.'); +INSERT INTO t1(docid,words) VALUES(1033018,'And Jacob came to Shalem, a city of Shechem, which is in the land of Canaan, when he came from Padanaram; and pitched his tent before the city.'); +INSERT INTO t1(docid,words) VALUES(1033019,'And he bought a parcel of a field, where he had spread his tent, at the hand of the children of Hamor, Shechem''s father, for an hundred pieces of money.'); +INSERT INTO t1(docid,words) VALUES(1033020,'And he erected there an altar, and called it EleloheIsrael.'); +INSERT INTO t1(docid,words) VALUES(1034001,'And Dinah the daughter of Leah, which she bare unto Jacob, went out to see the daughters of the land.'); +INSERT INTO t1(docid,words) VALUES(1034002,'And when Shechem the son of Hamor the Hivite, prince of the country, saw her, he took her, and lay with her, and defiled her.'); +INSERT INTO t1(docid,words) VALUES(1034003,'And his soul clave unto Dinah the daughter of Jacob, and he loved the damsel, and spake kindly unto the damsel.'); +INSERT INTO t1(docid,words) VALUES(1034004,'And Shechem spake unto his father Hamor, saying, Get me this damsel to wife.'); +INSERT INTO t1(docid,words) VALUES(1034005,'And Jacob heard that he had defiled Dinah his daughter: now his sons were with his cattle in the field: and Jacob held his peace until they were come.'); +INSERT INTO t1(docid,words) VALUES(1034006,'And Hamor the father of Shechem went out unto Jacob to commune with him.'); +INSERT INTO t1(docid,words) VALUES(1034007,'And the sons of Jacob came out of the field when they heard it: and the men were grieved, and they were very wroth, because he had wrought folly in Israel in lying with Jacob''s daughter: which thing ought not to be done.'); +INSERT INTO t1(docid,words) VALUES(1034008,'And Hamor communed with them, saying, The soul of my son Shechem longeth for your daughter: I pray you give her him to wife.'); +INSERT INTO t1(docid,words) VALUES(1034009,'And make ye marriages with us, and give your daughters unto us, and take our daughters unto you.'); +INSERT INTO t1(docid,words) VALUES(1034010,'And ye shall dwell with us: and the land shall be before you; dwell and trade ye therein, and get you possessions therein.'); +INSERT INTO t1(docid,words) VALUES(1034011,'And Shechem said unto her father and unto her brethren, Let me find grace in your eyes, and what ye shall say unto me I will give.'); +INSERT INTO t1(docid,words) VALUES(1034012,'Ask me never so much dowry and gift, and I will give according as ye shall say unto me: but give me the damsel to wife.'); +INSERT INTO t1(docid,words) VALUES(1034013,'And the sons of Jacob answered Shechem and Hamor his father deceitfully, and said, because he had defiled Dinah their sister:'); +INSERT INTO t1(docid,words) VALUES(1034014,'And they said unto them, We cannot do this thing, to give our sister to one that is uncircumcised; for that were a reproach unto us:'); +INSERT INTO t1(docid,words) VALUES(1034015,'But in this will we consent unto you: If ye will be as we be, that every male of you be circumcised;'); +INSERT INTO t1(docid,words) VALUES(1034016,'Then will we give our daughters unto you, and we will take your daughters to us, and we will dwell with you, and we will become one people.'); +INSERT INTO t1(docid,words) VALUES(1034017,'But if ye will not hearken unto us, to be circumcised; then will we take our daughter, and we will be gone.'); +INSERT INTO t1(docid,words) VALUES(1034018,'And their words pleased Hamor, and Shechem Hamor''s son.'); +INSERT INTO t1(docid,words) VALUES(1034019,'And the young man deferred not to do the thing, because he had delight in Jacob''s daughter: and he was more honourable than all the house of his father.'); +INSERT INTO t1(docid,words) VALUES(1034020,'And Hamor and Shechem his son came unto the gate of their city, and communed with the men of their city, saying,'); +INSERT INTO t1(docid,words) VALUES(1034021,'These men are peaceable with us; therefore let them dwell in the land, and trade therein; for the land, behold, it is large enough for them; let us take their daughters to us for wives, and let us give them our daughters.'); +INSERT INTO t1(docid,words) VALUES(1034022,'Only herein will the men consent unto us for to dwell with us, to be one people, if every male among us be circumcised, as they are circumcised.'); +INSERT INTO t1(docid,words) VALUES(1034023,'Shall not their cattle and their substance and every beast of their''s be our''s? only let us consent unto them, and they will dwell with us.'); +INSERT INTO t1(docid,words) VALUES(1034024,'And unto Hamor and unto Shechem his son hearkened all that went out of the gate of his city; and every male was circumcised, all that went out of the gate of his city.'); +INSERT INTO t1(docid,words) VALUES(1034025,'And it came to pass on the third day, when they were sore, that two of the sons of Jacob, Simeon and Levi, Dinah''s brethren, took each man his sword, and came upon the city boldly, and slew all the males.'); +INSERT INTO t1(docid,words) VALUES(1034026,'And they slew Hamor and Shechem his son with the edge of the sword, and took Dinah out of Shechem''s house, and went out.'); +INSERT INTO t1(docid,words) VALUES(1034027,'The sons of Jacob came upon the slain, and spoiled the city, because they had defiled their sister.'); +INSERT INTO t1(docid,words) VALUES(1034028,'They took their sheep, and their oxen, and their asses, and that which was in the city, and that which was in the field,'); +INSERT INTO t1(docid,words) VALUES(1034029,'And all their wealth, and all their little ones, and their wives took they captive, and spoiled even all that was in the house.'); +INSERT INTO t1(docid,words) VALUES(1034030,'And Jacob said to Simeon and Levi, Ye have troubled me to make me to stink among the inhabitants of the land, among the Canaanites and the Perizzites: and I being few in number, they shall gather themselves together against me, and slay me; and I shall be destroyed, I and my house.'); +INSERT INTO t1(docid,words) VALUES(1034031,'And they said, Should he deal with our sister as with an harlot?'); +INSERT INTO t1(docid,words) VALUES(1035001,'And God said unto Jacob, Arise, go up to Bethel, and dwell there: and make there an altar unto God, that appeared unto thee when thou fleddest from the face of Esau thy brother.'); +INSERT INTO t1(docid,words) VALUES(1035002,'Then Jacob said unto his household, and to all that were with him, Put away the strange gods that are among you, and be clean, and change your garments:'); +INSERT INTO t1(docid,words) VALUES(1035003,'And let us arise, and go up to Bethel; and I will make there an altar unto God, who answered me in the day of my distress, and was with me in the way which I went.'); +INSERT INTO t1(docid,words) VALUES(1035004,'And they gave unto Jacob all the strange gods which were in their hand, and all their earrings which were in their ears; and Jacob hid them under the oak which was by Shechem.'); +INSERT INTO t1(docid,words) VALUES(1035005,'And they journeyed: and the terror of God was upon the cities that were round about them, and they did not pursue after the sons of Jacob.'); +INSERT INTO t1(docid,words) VALUES(1035006,'So Jacob came to Luz, which is in the land of Canaan, that is, Bethel, he and all the people that were with him.'); +INSERT INTO t1(docid,words) VALUES(1035007,'And he built there an altar, and called the place Elbethel: because there God appeared unto him, when he fled from the face of his brother.'); +INSERT INTO t1(docid,words) VALUES(1035008,'But Deborah Rebekah''s nurse died, and she was buried beneath Bethel under an oak: and the name of it was called Allonbachuth.'); +INSERT INTO t1(docid,words) VALUES(1035009,'And God appeared unto Jacob again, when he came out of Padanaram, and blessed him.'); +INSERT INTO t1(docid,words) VALUES(1035010,'And God said unto him, Thy name is Jacob: thy name shall not be called any more Jacob, but Israel shall be thy name: and he called his name Israel.'); +INSERT INTO t1(docid,words) VALUES(1035011,'And God said unto him, I am God Almighty: be fruitful and multiply; a nation and a company of nations shall be of thee, and kings shall come out of thy loins;'); +INSERT INTO t1(docid,words) VALUES(1035012,'And the land which I gave Abraham and Isaac, to thee I will give it, and to thy seed after thee will I give the land.'); +INSERT INTO t1(docid,words) VALUES(1035013,'And God went up from him in the place where he talked with him.'); +INSERT INTO t1(docid,words) VALUES(1035014,'And Jacob set up a pillar in the place where he talked with him, even a pillar of stone: and he poured a drink offering thereon, and he poured oil thereon.'); +INSERT INTO t1(docid,words) VALUES(1035015,'And Jacob called the name of the place where God spake with him, Bethel.'); +INSERT INTO t1(docid,words) VALUES(1035016,'And they journeyed from Bethel; and there was but a little way to come to Ephrath: and Rachel travailed, and she had hard labour.'); +INSERT INTO t1(docid,words) VALUES(1035017,'And it came to pass, when she was in hard labour, that the midwife said unto her, Fear not; thou shalt have this son also.'); +INSERT INTO t1(docid,words) VALUES(1035018,'And it came to pass, as her soul was in departing, (for she died) that she called his name Benoni: but his father called him Benjamin.'); +INSERT INTO t1(docid,words) VALUES(1035019,'And Rachel died, and was buried in the way to Ephrath, which is Bethlehem.'); +INSERT INTO t1(docid,words) VALUES(1035020,'And Jacob set a pillar upon her grave: that is the pillar of Rachel''s grave unto this day.'); +INSERT INTO t1(docid,words) VALUES(1035021,'And Israel journeyed, and spread his tent beyond the tower of Edar.'); +INSERT INTO t1(docid,words) VALUES(1035022,'And it came to pass, when Israel dwelt in that land, that Reuben went and lay with Bilhah his father''s concubine: and Israel heard it. Now the sons of Jacob were twelve:'); +INSERT INTO t1(docid,words) VALUES(1035023,'The sons of Leah; Reuben, Jacob''s firstborn, and Simeon, and Levi, and Judah, and Issachar, and Zebulun:'); +INSERT INTO t1(docid,words) VALUES(1035024,'The sons of Rachel; Joseph, and Benjamin:'); +INSERT INTO t1(docid,words) VALUES(1035025,'And the sons of Bilhah, Rachel''s handmaid; Dan, and Naphtali:'); +INSERT INTO t1(docid,words) VALUES(1035026,'And the sons of Zilpah, Leah''s handmaid: Gad, and Asher: these are the sons of Jacob, which were born to him in Padanaram.'); +INSERT INTO t1(docid,words) VALUES(1035027,'And Jacob came unto Isaac his father unto Mamre, unto the city of Arbah, which is Hebron, where Abraham and Isaac sojourned.'); +INSERT INTO t1(docid,words) VALUES(1035028,'And the days of Isaac were an hundred and fourscore years.'); +INSERT INTO t1(docid,words) VALUES(1035029,'And Isaac gave up the ghost, and died, and was gathered unto his people, being old and full of days: and his sons Esau and Jacob buried him.'); +INSERT INTO t1(docid,words) VALUES(1036001,'Now these are the generations of Esau, who is Edom.'); +INSERT INTO t1(docid,words) VALUES(1036002,'Esau took his wives of the daughters of Canaan; Adah the daughter of Elon the Hittite, and Aholibamah the daughter of Anah the daughter of Zibeon the Hivite;'); +INSERT INTO t1(docid,words) VALUES(1036003,'And Bashemath Ishmael''s daughter, sister of Nebajoth.'); +INSERT INTO t1(docid,words) VALUES(1036004,'And Adah bare to Esau Eliphaz; and Bashemath bare Reuel;'); +INSERT INTO t1(docid,words) VALUES(1036005,'And Aholibamah bare Jeush, and Jaalam, and Korah: these are the sons of Esau, which were born unto him in the land of Canaan.'); +INSERT INTO t1(docid,words) VALUES(1036006,'And Esau took his wives, and his sons, and his daughters, and all the persons of his house, and his cattle, and all his beasts, and all his substance, which he had got in the land of Canaan; and went into the country from the face of his brother Jacob.'); +INSERT INTO t1(docid,words) VALUES(1036007,'For their riches were more than that they might dwell together; and the land wherein they were strangers could not bear them because of their cattle.'); +INSERT INTO t1(docid,words) VALUES(1036008,'Thus dwelt Esau in mount Seir: Esau is Edom.'); +INSERT INTO t1(docid,words) VALUES(1036009,'And these are the generations of Esau the father of the Edomites in mount Seir:'); +INSERT INTO t1(docid,words) VALUES(1036010,'These are the names of Esau''s sons; Eliphaz the son of Adah the wife of Esau, Reuel the son of Bashemath the wife of Esau.'); +INSERT INTO t1(docid,words) VALUES(1036011,'And the sons of Eliphaz were Teman, Omar, Zepho, and Gatam, and Kenaz.'); +INSERT INTO t1(docid,words) VALUES(1036012,'And Timna was concubine to Eliphaz Esau''s son; and she bare to Eliphaz Amalek: these were the sons of Adah Esau''s wife.'); +INSERT INTO t1(docid,words) VALUES(1036013,'And these are the sons of Reuel; Nahath, and Zerah, Shammah, and Mizzah: these were the sons of Bashemath Esau''s wife.'); +INSERT INTO t1(docid,words) VALUES(1036014,'And these were the sons of Aholibamah, the daughter of Anah the daughter of Zibeon, Esau''s wife: and she bare to Esau Jeush, and Jaalam, and Korah.'); +INSERT INTO t1(docid,words) VALUES(1036015,'These were dukes of the sons of Esau: the sons of Eliphaz the firstborn son of Esau; duke Teman, duke Omar, duke Zepho, duke Kenaz,'); +INSERT INTO t1(docid,words) VALUES(1036016,'Duke Korah, duke Gatam, and duke Amalek: these are the dukes that came of Eliphaz in the land of Edom; these were the sons of Adah.'); +INSERT INTO t1(docid,words) VALUES(1036017,'And these are the sons of Reuel Esau''s son; duke Nahath, duke Zerah, duke Shammah, duke Mizzah: these are the dukes that came of Reuel in the land of Edom; these are the sons of Bashemath Esau''s wife.'); +INSERT INTO t1(docid,words) VALUES(1036018,'And these are the sons of Aholibamah Esau''s wife; duke Jeush, duke Jaalam, duke Korah: these were the dukes that came of Aholibamah the daughter of Anah, Esau''s wife.'); +INSERT INTO t1(docid,words) VALUES(1036019,'These are the sons of Esau, who is Edom, and these are their dukes.'); +INSERT INTO t1(docid,words) VALUES(1036020,'These are the sons of Seir the Horite, who inhabited the land; Lotan, and Shobal, and Zibeon, and Anah,'); +INSERT INTO t1(docid,words) VALUES(1036021,'And Dishon, and Ezer, and Dishan: these are the dukes of the Horites, the children of Seir in the land of Edom.'); +INSERT INTO t1(docid,words) VALUES(1036022,'And the children of Lotan were Hori and Hemam; and Lotan''s sister was Timna.'); +INSERT INTO t1(docid,words) VALUES(1036023,'And the children of Shobal were these; Alvan, and Manahath, and Ebal, Shepho, and Onam.'); +INSERT INTO t1(docid,words) VALUES(1036024,'And these are the children of Zibeon; both Ajah, and Anah: this was that Anah that found the mules in the wilderness, as he fed the asses of Zibeon his father.'); +INSERT INTO t1(docid,words) VALUES(1036025,'And the children of Anah were these; Dishon, and Aholibamah the daughter of Anah.'); +INSERT INTO t1(docid,words) VALUES(1036026,'And these are the children of Dishon; Hemdan, and Eshban, and Ithran, and Cheran.'); +INSERT INTO t1(docid,words) VALUES(1036027,'The children of Ezer are these; Bilhan, and Zaavan, and Akan.'); +INSERT INTO t1(docid,words) VALUES(1036028,'The children of Dishan are these; Uz, and Aran.'); +INSERT INTO t1(docid,words) VALUES(1036029,'These are the dukes that came of the Horites; duke Lotan, duke Shobal, duke Zibeon, duke Anah,'); +INSERT INTO t1(docid,words) VALUES(1036030,'Duke Dishon, duke Ezer, duke Dishan: these are the dukes that came of Hori, among their dukes in the land of Seir.'); +INSERT INTO t1(docid,words) VALUES(1036031,'And these are the kings that reigned in the land of Edom, before there reigned any king over the children of Israel.'); +INSERT INTO t1(docid,words) VALUES(1036032,'And Bela the son of Beor reigned in Edom: and the name of his city was Dinhabah.'); +INSERT INTO t1(docid,words) VALUES(1036033,'And Bela died, and Jobab the son of Zerah of Bozrah reigned in his stead.'); +INSERT INTO t1(docid,words) VALUES(1036034,'And Jobab died, and Husham of the land of Temani reigned in his stead.'); +INSERT INTO t1(docid,words) VALUES(1036035,'And Husham died, and Hadad the son of Bedad, who smote Midian in the field of Moab, reigned in his stead: and the name of his city was Avith.'); +INSERT INTO t1(docid,words) VALUES(1036036,'And Hadad died, and Samlah of Masrekah reigned in his stead.'); +INSERT INTO t1(docid,words) VALUES(1036037,'And Samlah died, and Saul of Rehoboth by the river reigned in his stead.'); +INSERT INTO t1(docid,words) VALUES(1036038,'And Saul died, and Baalhanan the son of Achbor reigned in his stead.'); +INSERT INTO t1(docid,words) VALUES(1036039,'And Baalhanan the son of Achbor died, and Hadar reigned in his stead: and the name of his city was Pau; and his wife''s name was Mehetabel, the daughter of Matred, the daughter of Mezahab.'); +INSERT INTO t1(docid,words) VALUES(1036040,'And these are the names of the dukes that came of Esau, according to their families, after their places, by their names; duke Timnah, duke Alvah, duke Jetheth,'); +INSERT INTO t1(docid,words) VALUES(1036041,'Duke Aholibamah, duke Elah, duke Pinon,'); +INSERT INTO t1(docid,words) VALUES(1036042,'Duke Kenaz, duke Teman, duke Mibzar,'); +INSERT INTO t1(docid,words) VALUES(1036043,'Duke Magdiel, duke Iram: these be the dukes of Edom, according to their habitations in the land of their possession: he is Esau the father of the Edomites.'); +INSERT INTO t1(docid,words) VALUES(1037001,'And Jacob dwelt in the land wherein his father was a stranger, in the land of Canaan.'); +INSERT INTO t1(docid,words) VALUES(1037002,'These are the generations of Jacob. Joseph, being seventeen years old, was feeding the flock with his brethren; and the lad was with the sons of Bilhah, and with the sons of Zilpah, his father''s wives: and Joseph brought unto his father their evil report.'); +INSERT INTO t1(docid,words) VALUES(1037003,'Now Israel loved Joseph more than all his children, because he was the son of his old age: and he made him a coat of many colours.'); +INSERT INTO t1(docid,words) VALUES(1037004,'And when his brethren saw that their father loved him more than all his brethren, they hated him, and could not speak peaceably unto him.'); +INSERT INTO t1(docid,words) VALUES(1037005,'And Joseph dreamed a dream, and he told it his brethren: and they hated him yet the more.'); +INSERT INTO t1(docid,words) VALUES(1037006,'And he said unto them, Hear, I pray you, this dream which I have dreamed:'); +INSERT INTO t1(docid,words) VALUES(1037007,'For, behold, we were binding sheaves in the field, and, lo, my sheaf arose, and also stood upright; and, behold, your sheaves stood round about, and made obeisance to my sheaf.'); +INSERT INTO t1(docid,words) VALUES(1037008,'And his brethren said to him, Shalt thou indeed reign over us? or shalt thou indeed have dominion over us? And they hated him yet the more for his dreams, and for his words.'); +INSERT INTO t1(docid,words) VALUES(1037009,'And he dreamed yet another dream, and told it his brethren, and said, Behold, I have dreamed a dream more; and, behold, the sun and the moon and the eleven stars made obeisance to me.'); +INSERT INTO t1(docid,words) VALUES(1037010,'And he told it to his father, and to his brethren: and his father rebuked him, and said unto him, What is this dream that thou hast dreamed? Shall I and thy mother and thy brethren indeed come to bow down ourselves to thee to the earth?'); +INSERT INTO t1(docid,words) VALUES(1037011,'And his brethren envied him; but his father observed the saying.'); +INSERT INTO t1(docid,words) VALUES(1037012,'And his brethren went to feed their father''s flock in Shechem.'); +INSERT INTO t1(docid,words) VALUES(1037013,'And Israel said unto Joseph, Do not thy brethren feed the flock in Shechem? come, and I will send thee unto them. And he said to him, Here am I.'); +INSERT INTO t1(docid,words) VALUES(1037014,'And he said to him, Go, I pray thee, see whether it be well with thy brethren, and well with the flocks; and bring me word again. So he sent him out of the vale of Hebron, and he came to Shechem.'); +INSERT INTO t1(docid,words) VALUES(1037015,'And a certain man found him, and, behold, he was wandering in the field: and the man asked him, saying, What seekest thou?'); +INSERT INTO t1(docid,words) VALUES(1037016,'And he said, I seek my brethren: tell me, I pray thee, where they feed their flocks.'); +INSERT INTO t1(docid,words) VALUES(1037017,'And the man said, They are departed hence; for I heard them say, Let us go to Dothan. And Joseph went after his brethren, and found them in Dothan.'); +INSERT INTO t1(docid,words) VALUES(1037018,'And when they saw him afar off, even before he came near unto them, they conspired against him to slay him.'); +INSERT INTO t1(docid,words) VALUES(1037019,'And they said one to another, Behold, this dreamer cometh.'); +INSERT INTO t1(docid,words) VALUES(1037020,'Come now therefore, and let us slay him, and cast him into some pit, and we will say, Some evil beast hath devoured him: and we shall see what will become of his dreams.'); +INSERT INTO t1(docid,words) VALUES(1037021,'And Reuben heard it, and he delivered him out of their hands; and said, Let us not kill him.'); +INSERT INTO t1(docid,words) VALUES(1037022,'And Reuben said unto them, Shed no blood, but cast him into this pit that is in the wilderness, and lay no hand upon him; that he might rid him out of their hands, to deliver him to his father again.'); +INSERT INTO t1(docid,words) VALUES(1037023,'And it came to pass, when Joseph was come unto his brethren, that they stript Joseph out of his coat, his coat of many colours that was on him;'); +INSERT INTO t1(docid,words) VALUES(1037024,'And they took him, and cast him into a pit: and the pit was empty, there was no water in it.'); +INSERT INTO t1(docid,words) VALUES(1037025,'And they sat down to eat bread: and they lifted up their eyes and looked, and, behold, a company of Ishmeelites came from Gilead with their camels bearing spicery and balm and myrrh, going to carry it down to Egypt.'); +INSERT INTO t1(docid,words) VALUES(1037026,'And Judah said unto his brethren, What profit is it if we slay our brother, and conceal his blood?'); +INSERT INTO t1(docid,words) VALUES(1037027,'Come, and let us sell him to the Ishmeelites, and let not our hand be upon him; for he is our brother and our flesh. And his brethren were content.'); +INSERT INTO t1(docid,words) VALUES(1037028,'Then there passed by Midianites merchantmen; and they drew and lifted up Joseph out of the pit, and sold Joseph to the Ishmeelites for twenty pieces of silver: and they brought Joseph into Egypt.'); +INSERT INTO t1(docid,words) VALUES(1037029,'And Reuben returned unto the pit; and, behold, Joseph was not in the pit; and he rent his clothes.'); +INSERT INTO t1(docid,words) VALUES(1037030,'And he returned unto his brethren, and said, The child is not; and I, whither shall I go?'); +INSERT INTO t1(docid,words) VALUES(1037031,'And they took Joseph''s coat, and killed a kid of the goats, and dipped the coat in the blood;'); +INSERT INTO t1(docid,words) VALUES(1037032,'And they sent the coat of many colours, and they brought it to their father; and said, This have we found: know now whether it be thy son''s coat or no.'); +INSERT INTO t1(docid,words) VALUES(1037033,'And he knew it, and said, It is my son''s coat; an evil beast hath devoured him; Joseph is without doubt rent in pieces.'); +INSERT INTO t1(docid,words) VALUES(1037034,'And Jacob rent his clothes, and put sackcloth upon his loins, and mourned for his son many days.'); +INSERT INTO t1(docid,words) VALUES(1037035,'And all his sons and all his daughters rose up to comfort him; but he refused to be comforted; and he said, For I will go down into the grave unto my son mourning. Thus his father wept for him.'); +INSERT INTO t1(docid,words) VALUES(1037036,'And the Midianites sold him into Egypt unto Potiphar, an officer of Pharaoh''s, and captain of the guard.'); +INSERT INTO t1(docid,words) VALUES(1038001,'And it came to pass at that time, that Judah went down from his brethren, and turned in to a certain Adullamite, whose name was Hirah.'); +INSERT INTO t1(docid,words) VALUES(1038002,'And Judah saw there a daughter of a certain Canaanite, whose name was Shuah; and he took her, and went in unto her.'); +INSERT INTO t1(docid,words) VALUES(1038003,'And she conceived, and bare a son; and he called his name Er.'); +INSERT INTO t1(docid,words) VALUES(1038004,'And she conceived again, and bare a son; and she called his name Onan.'); +INSERT INTO t1(docid,words) VALUES(1038005,'And she yet again conceived, and bare a son; and called his name Shelah: and he was at Chezib, when she bare him.'); +INSERT INTO t1(docid,words) VALUES(1038006,'And Judah took a wife for Er his firstborn, whose name was Tamar.'); +INSERT INTO t1(docid,words) VALUES(1038007,'And Er, Judah''s firstborn, was wicked in the sight of the LORD; and the LORD slew him.'); +INSERT INTO t1(docid,words) VALUES(1038008,'And Judah said unto Onan, Go in unto thy brother''s wife, and marry her, and raise up seed to thy brother.'); +INSERT INTO t1(docid,words) VALUES(1038009,'And Onan knew that the seed should not be his; and it came to pass, when he went in unto his brother''s wife, that he spilled it on the ground, lest that he should give seed to his brother.'); +INSERT INTO t1(docid,words) VALUES(1038010,'And the thing which he did displeased the LORD: wherefore he slew him also.'); +INSERT INTO t1(docid,words) VALUES(1038011,'Then said Judah to Tamar his daughter in law, Remain a widow at thy father''s house, till Shelah my son be grown: for he said, Lest peradventure he die also, as his brethren did. And Tamar went and dwelt in her father''s house.'); +INSERT INTO t1(docid,words) VALUES(1038012,'And in process of time the daughter of Shuah Judah''s wife died; and Judah was comforted, and went up unto his sheepshearers to Timnath, he and his friend Hirah the Adullamite.'); +INSERT INTO t1(docid,words) VALUES(1038013,'And it was told Tamar, saying, Behold thy father in law goeth up to Timnath to shear his sheep.'); +INSERT INTO t1(docid,words) VALUES(1038014,'And she put her widow''s garments off from her, and covered her with a vail, and wrapped herself, and sat in an open place, which is by the way to Timnath; for she saw that Shelah was grown, and she was not given unto him to wife.'); +INSERT INTO t1(docid,words) VALUES(1038015,'When Judah saw her, he thought her to be an harlot; because she had covered her face.'); +INSERT INTO t1(docid,words) VALUES(1038016,'And he turned unto her by the way, and said, Go to, I pray thee, let me come in unto thee; (for he knew not that she was his daughter in law.) And she said, What wilt thou give me, that thou mayest come in unto me?'); +INSERT INTO t1(docid,words) VALUES(1038017,'And he said, I will send thee a kid from the flock. And she said, Wilt thou give me a pledge, till thou send it?'); +INSERT INTO t1(docid,words) VALUES(1038018,'And he said, What pledge shall I give thee? And she said, Thy signet, and thy bracelets, and thy staff that is in thine hand. And he gave it her, and came in unto her, and she conceived by him.'); +INSERT INTO t1(docid,words) VALUES(1038019,'And she arose, and went away, and laid by her vail from her, and put on the garments of her widowhood.'); +INSERT INTO t1(docid,words) VALUES(1038020,'And Judah sent the kid by the hand of his friend the Adullamite, to receive his pledge from the woman''s hand: but he found her not.'); +INSERT INTO t1(docid,words) VALUES(1038021,'Then he asked the men of that place, saying, Where is the harlot, that was openly by the way side? And they said, There was no harlot in this place.'); +INSERT INTO t1(docid,words) VALUES(1038022,'And he returned to Judah, and said, I cannot find her; and also the men of the place said, that there was no harlot in this place.'); +INSERT INTO t1(docid,words) VALUES(1038023,'And Judah said, Let her take it to her, lest we be shamed: behold, I sent this kid, and thou hast not found her.'); +INSERT INTO t1(docid,words) VALUES(1038024,'And it came to pass about three months after, that it was told Judah, saying, Tamar thy daughter in law hath played the harlot; and also, behold, she is with child by whoredom. And Judah said, Bring her forth, and let her be burnt.'); +INSERT INTO t1(docid,words) VALUES(1038025,'When she was brought forth, she sent to her father in law, saying, By the man, whose these are, am I with child: and she said, Discern, I pray thee, whose are these, the signet, and bracelets, and staff.'); +INSERT INTO t1(docid,words) VALUES(1038026,'And Judah acknowledged them, and said, She hath been more righteous than I; because that I gave her not to Shelah my son. And he knew her again no more.'); +INSERT INTO t1(docid,words) VALUES(1038027,'And it came to pass in the time of her travail, that, behold, twins were in her womb.'); +INSERT INTO t1(docid,words) VALUES(1038028,'And it came to pass, when she travailed, that the one put out his hand: and the midwife took and bound upon his hand a scarlet thread, saying, This came out first.'); +INSERT INTO t1(docid,words) VALUES(1038029,'And it came to pass, as he drew back his hand, that, behold, his brother came out: and she said, How hast thou broken forth? this breach be upon thee: therefore his name was called Pharez.'); +INSERT INTO t1(docid,words) VALUES(1038030,'And afterward came out his brother, that had the scarlet thread upon his hand: and his name was called Zarah.'); +INSERT INTO t1(docid,words) VALUES(1039001,'And Joseph was brought down to Egypt; and Potiphar, an officer of Pharaoh, captain of the guard, an Egyptian, bought him of the hands of the Ishmeelites, which had brought him down thither.'); +INSERT INTO t1(docid,words) VALUES(1039002,'And the LORD was with Joseph, and he was a prosperous man; and he was in the house of his master the Egyptian.'); +INSERT INTO t1(docid,words) VALUES(1039003,'And his master saw that the LORD was with him, and that the LORD made all that he did to prosper in his hand.'); +INSERT INTO t1(docid,words) VALUES(1039004,'And Joseph found grace in his sight, and he served him: and he made him overseer over his house, and all that he had he put into his hand.'); +INSERT INTO t1(docid,words) VALUES(1039005,'And it came to pass from the time that he had made him overseer in his house, and over all that he had, that the LORD blessed the Egyptian''s house for Joseph''s sake; and the blessing of the LORD was upon all that he had in the house, and in the field.'); +INSERT INTO t1(docid,words) VALUES(1039006,'And he left all that he had in Joseph''s hand; and he knew not ought he had, save the bread which he did eat. And Joseph was a goodly person, and well favoured.'); +INSERT INTO t1(docid,words) VALUES(1039007,'And it came to pass after these things, that his master''s wife cast her eyes upon Joseph; and she said, Lie with me.'); +INSERT INTO t1(docid,words) VALUES(1039008,'But he refused, and said unto his master''s wife, Behold, my master wotteth not what is with me in the house, and he hath committed all that he hath to my hand;'); +INSERT INTO t1(docid,words) VALUES(1039009,'There is none greater in this house than I; neither hath he kept back any thing from me but thee, because thou art his wife: how then can I do this great wickedness, and sin against God?'); +INSERT INTO t1(docid,words) VALUES(1039010,'And it came to pass, as she spake to Joseph day by day, that he hearkened not unto her, to lie by her, or to be with her.'); +INSERT INTO t1(docid,words) VALUES(1039011,'And it came to pass about this time, that Joseph went into the house to do his business; and there was none of the men of the house there within.'); +INSERT INTO t1(docid,words) VALUES(1039012,'And she caught him by his garment, saying, Lie with me: and he left his garment in her hand, and fled, and got him out.'); +INSERT INTO t1(docid,words) VALUES(1039013,'And it came to pass, when she saw that he had left his garment in her hand, and was fled forth,'); +INSERT INTO t1(docid,words) VALUES(1039014,'That she called unto the men of her house, and spake unto them, saying, See, he hath brought in an Hebrew unto us to mock us; he came in unto me to lie with me, and I cried with a loud voice:'); +INSERT INTO t1(docid,words) VALUES(1039015,'And it came to pass, when he heard that I lifted up my voice and cried, that he left his garment with me, and fled, and got him out.'); +INSERT INTO t1(docid,words) VALUES(1039016,'And she laid up his garment by her, until his lord came home.'); +INSERT INTO t1(docid,words) VALUES(1039017,'And she spake unto him according to these words, saying, The Hebrew servant, which thou hast brought unto us, came in unto me to mock me:'); +INSERT INTO t1(docid,words) VALUES(1039018,'And it came to pass, as I lifted up my voice and cried, that he left his garment with me, and fled out.'); +INSERT INTO t1(docid,words) VALUES(1039019,'And it came to pass, when his master heard the words of his wife, which she spake unto him, saying, After this manner did thy servant to me; that his wrath was kindled.'); +INSERT INTO t1(docid,words) VALUES(1039020,'And Joseph''s master took him, and put him into the prison, a place where the king''s prisoners were bound: and he was there in the prison.'); +INSERT INTO t1(docid,words) VALUES(1039021,'But the LORD was with Joseph, and shewed him mercy, and gave him favour in the sight of the keeper of the prison.'); +INSERT INTO t1(docid,words) VALUES(1039022,'And the keeper of the prison committed to Joseph''s hand all the prisoners that were in the prison; and whatsoever they did there, he was the doer of it.'); +INSERT INTO t1(docid,words) VALUES(1039023,'The keeper of the prison looked not to any thing that was under his hand; because the LORD was with him, and that which he did, the LORD made it to prosper.'); +INSERT INTO t1(docid,words) VALUES(1040001,'And it came to pass after these things, that the butler of the king of Egypt and his baker had offended their lord the king of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1040002,'And Pharaoh was wroth against two of his officers, against the chief of the butlers, and against the chief of the bakers.'); +INSERT INTO t1(docid,words) VALUES(1040003,'And he put them in ward in the house of the captain of the guard, into the prison, the place where Joseph was bound.'); +INSERT INTO t1(docid,words) VALUES(1040004,'And the captain of the guard charged Joseph with them, and he served them: and they continued a season in ward.'); +INSERT INTO t1(docid,words) VALUES(1040005,'And they dreamed a dream both of them, each man his dream in one night, each man according to the interpretation of his dream, the butler and the baker of the king of Egypt, which were bound in the prison.'); +INSERT INTO t1(docid,words) VALUES(1040006,'And Joseph came in unto them in the morning, and looked upon them, and, behold, they were sad.'); +INSERT INTO t1(docid,words) VALUES(1040007,'And he asked Pharaoh''s officers that were with him in the ward of his lord''s house, saying, Wherefore look ye so sadly to day?'); +INSERT INTO t1(docid,words) VALUES(1040008,'And they said unto him, We have dreamed a dream, and there is no interpreter of it. And Joseph said unto them, Do not interpretations belong to God? tell me them, I pray you.'); +INSERT INTO t1(docid,words) VALUES(1040009,'And the chief butler told his dream to Joseph, and said to him, In my dream, behold, a vine was before me;'); +INSERT INTO t1(docid,words) VALUES(1040010,'And in the vine were three branches: and it was as though it budded, and her blossoms shot forth; and the clusters thereof brought forth ripe grapes:'); +INSERT INTO t1(docid,words) VALUES(1040011,'And Pharaoh''s cup was in my hand: and I took the grapes, and pressed them into Pharaoh''s cup, and I gave the cup into Pharaoh''s hand.'); +INSERT INTO t1(docid,words) VALUES(1040012,'And Joseph said unto him, This is the interpretation of it: The three branches are three days:'); +INSERT INTO t1(docid,words) VALUES(1040013,'Yet within three days shall Pharaoh lift up thine head, and restore thee unto thy place: and thou shalt deliver Pharaoh''s cup into his hand, after the former manner when thou wast his butler.'); +INSERT INTO t1(docid,words) VALUES(1040014,'But think on me when it shall be well with thee, and shew kindness, I pray thee, unto me, and make mention of me unto Pharaoh, and bring me out of this house:'); +INSERT INTO t1(docid,words) VALUES(1040015,'For indeed I was stolen away out of the land of the Hebrews: and here also have I done nothing that they should put me into the dungeon.'); +INSERT INTO t1(docid,words) VALUES(1040016,'When the chief baker saw that the interpretation was good, he said unto Joseph, I also was in my dream, and, behold, I had three white baskets on my head:'); +INSERT INTO t1(docid,words) VALUES(1040017,'And in the uppermost basket there was of all manner of bakemeats for Pharaoh; and the birds did eat them out of the basket upon my head.'); +INSERT INTO t1(docid,words) VALUES(1040018,'And Joseph answered and said, This is the interpretation thereof: The three baskets are three days:'); +INSERT INTO t1(docid,words) VALUES(1040019,'Yet within three days shall Pharaoh lift up thy head from off thee, and shall hang thee on a tree; and the birds shall eat thy flesh from off thee.'); +INSERT INTO t1(docid,words) VALUES(1040020,'And it came to pass the third day, which was Pharaoh''s birthday, that he made a feast unto all his servants: and he lifted up the head of the chief butler and of the chief baker among his servants.'); +INSERT INTO t1(docid,words) VALUES(1040021,'And he restored the chief butler unto his butlership again; and he gave the cup into Pharaoh''s hand:'); +INSERT INTO t1(docid,words) VALUES(1040022,'But he hanged the chief baker: as Joseph had interpreted to them.'); +INSERT INTO t1(docid,words) VALUES(1040023,'Yet did not the chief butler remember Joseph, but forgat him.'); +INSERT INTO t1(docid,words) VALUES(1041001,'And it came to pass at the end of two full years, that Pharaoh dreamed: and, behold, he stood by the river.'); +INSERT INTO t1(docid,words) VALUES(1041002,'And, behold, there came up out of the river seven well favoured kine and fatfleshed; and they fed in a meadow.'); +INSERT INTO t1(docid,words) VALUES(1041003,'And, behold, seven other kine came up after them out of the river, ill favoured and leanfleshed; and stood by the other kine upon the brink of the river.'); +INSERT INTO t1(docid,words) VALUES(1041004,'And the ill favoured and leanfleshed kine did eat up the seven well favoured and fat kine. So Pharaoh awoke.'); +INSERT INTO t1(docid,words) VALUES(1041005,'And he slept and dreamed the second time: and, behold, seven ears of corn came up upon one stalk, rank and good.'); +INSERT INTO t1(docid,words) VALUES(1041006,'And, behold, seven thin ears and blasted with the east wind sprung up after them.'); +INSERT INTO t1(docid,words) VALUES(1041007,'And the seven thin ears devoured the seven rank and full ears. And Pharaoh awoke, and, behold, it was a dream.'); +INSERT INTO t1(docid,words) VALUES(1041008,'And it came to pass in the morning that his spirit was troubled; and he sent and called for all the magicians of Egypt, and all the wise men thereof: and Pharaoh told them his dream; but there was none that could interpret them unto Pharaoh.'); +INSERT INTO t1(docid,words) VALUES(1041009,'Then spake the chief butler unto Pharaoh, saying, I do remember my faults this day:'); +INSERT INTO t1(docid,words) VALUES(1041010,'Pharaoh was wroth with his servants, and put me in ward in the captain of the guard''s house, both me and the chief baker:'); +INSERT INTO t1(docid,words) VALUES(1041011,'And we dreamed a dream in one night, I and he; we dreamed each man according to the interpretation of his dream.'); +INSERT INTO t1(docid,words) VALUES(1041012,'And there was there with us a young man, an Hebrew, servant to the captain of the guard; and we told him, and he interpreted to us our dreams; to each man according to his dream he did interpret.'); +INSERT INTO t1(docid,words) VALUES(1041013,'And it came to pass, as he interpreted to us, so it was; me he restored unto mine office, and him he hanged.'); +INSERT INTO t1(docid,words) VALUES(1041014,'Then Pharaoh sent and called Joseph, and they brought him hastily out of the dungeon: and he shaved himself, and changed his raiment, and came in unto Pharaoh.'); +INSERT INTO t1(docid,words) VALUES(1041015,'And Pharaoh said unto Joseph, I have dreamed a dream, and there is none that can interpret it: and I have heard say of thee, that thou canst understand a dream to interpret it.'); +INSERT INTO t1(docid,words) VALUES(1041016,'And Joseph answered Pharaoh, saying, It is not in me: God shall give Pharaoh an answer of peace.'); +INSERT INTO t1(docid,words) VALUES(1041017,'And Pharaoh said unto Joseph, In my dream, behold, I stood upon the bank of the river:'); +INSERT INTO t1(docid,words) VALUES(1041018,'And, behold, there came up out of the river seven kine, fatfleshed and well favoured; and they fed in a meadow:'); +INSERT INTO t1(docid,words) VALUES(1041019,'And, behold, seven other kine came up after them, poor and very ill favoured and leanfleshed, such as I never saw in all the land of Egypt for badness:'); +INSERT INTO t1(docid,words) VALUES(1041020,'And the lean and the ill favoured kine did eat up the first seven fat kine:'); +INSERT INTO t1(docid,words) VALUES(1041021,'And when they had eaten them up, it could not be known that they had eaten them; but they were still ill favoured, as at the beginning. So I awoke.'); +INSERT INTO t1(docid,words) VALUES(1041022,'And I saw in my dream, and, behold, seven ears came up in one stalk, full and good:'); +INSERT INTO t1(docid,words) VALUES(1041023,'And, behold, seven ears, withered, thin, and blasted with the east wind, sprung up after them:'); +INSERT INTO t1(docid,words) VALUES(1041024,'And the thin ears devoured the seven good ears: and I told this unto the magicians; but there was none that could declare it to me.'); +INSERT INTO t1(docid,words) VALUES(1041025,'And Joseph said unto Pharaoh, The dream of Pharaoh is one: God hath shewed Pharaoh what he is about to do.'); +INSERT INTO t1(docid,words) VALUES(1041026,'The seven good kine are seven years; and the seven good ears are seven years: the dream is one.'); +INSERT INTO t1(docid,words) VALUES(1041027,'And the seven thin and ill favoured kine that came up after them are seven years; and the seven empty ears blasted with the east wind shall be seven years of famine.'); +INSERT INTO t1(docid,words) VALUES(1041028,'This is the thing which I have spoken unto Pharaoh: What God is about to do he sheweth unto Pharaoh.'); +INSERT INTO t1(docid,words) VALUES(1041029,'Behold, there come seven years of great plenty throughout all the land of Egypt:'); +INSERT INTO t1(docid,words) VALUES(1041030,'And there shall arise after them seven years of famine; and all the plenty shall be forgotten in the land of Egypt; and the famine shall consume the land;'); +INSERT INTO t1(docid,words) VALUES(1041031,'And the plenty shall not be known in the land by reason of that famine following; for it shall be very grievous.'); +INSERT INTO t1(docid,words) VALUES(1041032,'And for that the dream was doubled unto Pharaoh twice; it is because the thing is established by God, and God will shortly bring it to pass.'); +INSERT INTO t1(docid,words) VALUES(1041033,'Now therefore let Pharaoh look out a man discreet and wise, and set him over the land of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1041034,'Let Pharaoh do this, and let him appoint officers over the land, and take up the fifth part of the land of Egypt in the seven plenteous years.'); +INSERT INTO t1(docid,words) VALUES(1041035,'And let them gather all the food of those good years that come, and lay up corn under the hand of Pharaoh, and let them keep food in the cities.'); +INSERT INTO t1(docid,words) VALUES(1041036,'And that food shall be for store to the land against the seven years of famine, which shall be in the land of Egypt; that the land perish not through the famine.'); +INSERT INTO t1(docid,words) VALUES(1041037,'And the thing was good in the eyes of Pharaoh, and in the eyes of all his servants.'); +INSERT INTO t1(docid,words) VALUES(1041038,'And Pharaoh said unto his servants, Can we find such a one as this is, a man in whom the Spirit of God is?'); +INSERT INTO t1(docid,words) VALUES(1041039,'And Pharaoh said unto Joseph, Forasmuch as God hath shewed thee all this, there is none so discreet and wise as thou art:'); +INSERT INTO t1(docid,words) VALUES(1041040,'Thou shalt be over my house, and according unto thy word shall all my people be ruled: only in the throne will I be greater than thou.'); +INSERT INTO t1(docid,words) VALUES(1041041,'And Pharaoh said unto Joseph, See, I have set thee over all the land of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1041042,'And Pharaoh took off his ring from his hand, and put it upon Joseph''s hand, and arrayed him in vestures of fine linen, and put a gold chain about his neck;'); +INSERT INTO t1(docid,words) VALUES(1041043,'And he made him to ride in the second chariot which he had; and they cried before him, Bow the knee: and he made him ruler over all the land of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1041044,'And Pharaoh said unto Joseph, I am Pharaoh, and without thee shall no man lift up his hand or foot in all the land of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1041045,'And Pharaoh called Joseph''s name Zaphnathpaaneah; and he gave him to wife Asenath the daughter of Potipherah priest of On. And Joseph went out over all the land of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1041046,'And Joseph was thirty years old when he stood before Pharaoh king of Egypt. And Joseph went out from the presence of Pharaoh, and went throughout all the land of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1041047,'And in the seven plenteous years the earth brought forth by handfuls.'); +INSERT INTO t1(docid,words) VALUES(1041048,'And he gathered up all the food of the seven years, which were in the land of Egypt, and laid up the food in the cities: the food of the field, which was round about every city, laid he up in the same.'); +INSERT INTO t1(docid,words) VALUES(1041049,'And Joseph gathered corn as the sand of the sea, very much, until he left numbering; for it was without number.'); +INSERT INTO t1(docid,words) VALUES(1041050,'And unto Joseph were born two sons before the years of famine came, which Asenath the daughter of Potipherah priest of On bare unto him.'); +INSERT INTO t1(docid,words) VALUES(1041051,'And Joseph called the name of the firstborn Manasseh: For God, said he, hath made me forget all my toil, and all my father''s house.'); +INSERT INTO t1(docid,words) VALUES(1041052,'And the name of the second called he Ephraim: For God hath caused me to be fruitful in the land of my affliction.'); +INSERT INTO t1(docid,words) VALUES(1041053,'And the seven years of plenteousness, that was in the land of Egypt, were ended.'); +INSERT INTO t1(docid,words) VALUES(1041054,'And the seven years of dearth began to come, according as Joseph had said: and the dearth was in all lands; but in all the land of Egypt there was bread.'); +INSERT INTO t1(docid,words) VALUES(1041055,'And when all the land of Egypt was famished, the people cried to Pharaoh for bread: and Pharaoh said unto all the Egyptians, Go unto Joseph; what he saith to you, do.'); +INSERT INTO t1(docid,words) VALUES(1041056,'And the famine was over all the face of the earth: and Joseph opened all the storehouses, and sold unto the Egyptians; and the famine waxed sore in the land of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1041057,'And all countries came into Egypt to Joseph for to buy corn; because that the famine was so sore in all lands.'); +INSERT INTO t1(docid,words) VALUES(1042001,'Now when Jacob saw that there was corn in Egypt, Jacob said unto his sons, Why do ye look one upon another?'); +INSERT INTO t1(docid,words) VALUES(1042002,'And he said, Behold, I have heard that there is corn in Egypt: get you down thither, and buy for us from thence; that we may live, and not die.'); +INSERT INTO t1(docid,words) VALUES(1042003,'And Joseph''s ten brethren went down to buy corn in Egypt.'); +INSERT INTO t1(docid,words) VALUES(1042004,'But Benjamin, Joseph''s brother, Jacob sent not with his brethren; for he said, Lest peradventure mischief befall him.'); +INSERT INTO t1(docid,words) VALUES(1042005,'And the sons of Israel came to buy corn among those that came: for the famine was in the land of Canaan.'); +INSERT INTO t1(docid,words) VALUES(1042006,'And Joseph was the governor over the land, and he it was that sold to all the people of the land: and Joseph''s brethren came, and bowed down themselves before him with their faces to the earth.'); +INSERT INTO t1(docid,words) VALUES(1042007,'And Joseph saw his brethren, and he knew them, but made himself strange unto them, and spake roughly unto them; and he said unto them, Whence come ye? And they said, From the land of Canaan to buy food.'); +INSERT INTO t1(docid,words) VALUES(1042008,'And Joseph knew his brethren, but they knew not him.'); +INSERT INTO t1(docid,words) VALUES(1042009,'And Joseph remembered the dreams which he dreamed of them, and said unto them, Ye are spies; to see the nakedness of the land ye are come.'); +INSERT INTO t1(docid,words) VALUES(1042010,'And they said unto him, Nay, my lord, but to buy food are thy servants come.'); +INSERT INTO t1(docid,words) VALUES(1042011,'We are all one man''s sons; we are true men, thy servants are no spies.'); +INSERT INTO t1(docid,words) VALUES(1042012,'And he said unto them, Nay, but to see the nakedness of the land ye are come.'); +INSERT INTO t1(docid,words) VALUES(1042013,'And they said, Thy servants are twelve brethren, the sons of one man in the land of Canaan; and, behold, the youngest is this day with our father, and one is not.'); +INSERT INTO t1(docid,words) VALUES(1042014,'And Joseph said unto them, That is it that I spake unto you, saying, Ye are spies:'); +INSERT INTO t1(docid,words) VALUES(1042015,'Hereby ye shall be proved: By the life of Pharaoh ye shall not go forth hence, except your youngest brother come hither.'); +INSERT INTO t1(docid,words) VALUES(1042016,'Send one of you, and let him fetch your brother, and ye shall be kept in prison, that your words may be proved, whether there be any truth in you: or else by the life of Pharaoh surely ye are spies.'); +INSERT INTO t1(docid,words) VALUES(1042017,'And he put them all together into ward three days.'); +INSERT INTO t1(docid,words) VALUES(1042018,'And Joseph said unto them the third day, This do, and live; for I fear God:'); +INSERT INTO t1(docid,words) VALUES(1042019,'If ye be true men, let one of your brethren be bound in the house of your prison: go ye, carry corn for the famine of your houses:'); +INSERT INTO t1(docid,words) VALUES(1042020,'But bring your youngest brother unto me; so shall your words be verified, and ye shall not die. And they did so.'); +INSERT INTO t1(docid,words) VALUES(1042021,'And they said one to another, We are verily guilty concerning our brother, in that we saw the anguish of his soul, when he besought us, and we would not hear; therefore is this distress come upon us.'); +INSERT INTO t1(docid,words) VALUES(1042022,'And Reuben answered them, saying, Spake I not unto you, saying, Do not sin against the child; and ye would not hear? therefore, behold, also his blood is required.'); +INSERT INTO t1(docid,words) VALUES(1042023,'And they knew not that Joseph understood them; for he spake unto them by an interpreter.'); +INSERT INTO t1(docid,words) VALUES(1042024,'And he turned himself about from them, and wept; and returned to them again, and communed with them, and took from them Simeon, and bound him before their eyes.'); +INSERT INTO t1(docid,words) VALUES(1042025,'Then Joseph commanded to fill their sacks with corn, and to restore every man''s money into his sack, and to give them provision for the way: and thus did he unto them.'); +INSERT INTO t1(docid,words) VALUES(1042026,'And they laded their asses with the corn, and departed thence.'); +INSERT INTO t1(docid,words) VALUES(1042027,'And as one of them opened his sack to give his ass provender in the inn, he espied his money; for, behold, it was in his sack''s mouth.'); +INSERT INTO t1(docid,words) VALUES(1042028,'And he said unto his brethren, My money is restored; and, lo, it is even in my sack: and their heart failed them, and they were afraid, saying one to another, What is this that God hath done unto us?'); +INSERT INTO t1(docid,words) VALUES(1042029,'And they came unto Jacob their father unto the land of Canaan, and told him all that befell unto them; saying,'); +INSERT INTO t1(docid,words) VALUES(1042030,'The man, who is the lord of the land, spake roughly to us, and took us for spies of the country.'); +INSERT INTO t1(docid,words) VALUES(1042031,'And we said unto him, We are true men; we are no spies:'); +INSERT INTO t1(docid,words) VALUES(1042032,'We be twelve brethren, sons of our father; one is not, and the youngest is this day with our father in the land of Canaan.'); +INSERT INTO t1(docid,words) VALUES(1042033,'And the man, the lord of the country, said unto us, Hereby shall I know that ye are true men; leave one of your brethren here with me, and take food for the famine of your households, and be gone:'); +INSERT INTO t1(docid,words) VALUES(1042034,'And bring your youngest brother unto me: then shall I know that ye are no spies, but that ye are true men: so will I deliver you your brother, and ye shall traffick in the land.'); +INSERT INTO t1(docid,words) VALUES(1042035,'And it came to pass as they emptied their sacks, that, behold, every man''s bundle of money was in his sack: and when both they and their father saw the bundles of money, they were afraid.'); +INSERT INTO t1(docid,words) VALUES(1042036,'And Jacob their father said unto them, Me have ye bereaved of my children: Joseph is not, and Simeon is not, and ye will take Benjamin away: all these things are against me.'); +INSERT INTO t1(docid,words) VALUES(1042037,'And Reuben spake unto his father, saying, Slay my two sons, if I bring him not to thee: deliver him into my hand, and I will bring him to thee again.'); +INSERT INTO t1(docid,words) VALUES(1042038,'And he said, My son shall not go down with you; for his brother is dead, and he is left alone: if mischief befall him by the way in the which ye go, then shall ye bring down my gray hairs with sorrow to the grave.'); +INSERT INTO t1(docid,words) VALUES(1043001,'And the famine was sore in the land.'); +INSERT INTO t1(docid,words) VALUES(1043002,'And it came to pass, when they had eaten up the corn which they had brought out of Egypt, their father said unto them, Go again, buy us a little food.'); +INSERT INTO t1(docid,words) VALUES(1043003,'And Judah spake unto him, saying, The man did solemnly protest unto us, saying, Ye shall not see my face, except your brother be with you.'); +INSERT INTO t1(docid,words) VALUES(1043004,'If thou wilt send our brother with us, we will go down and buy thee food:'); +INSERT INTO t1(docid,words) VALUES(1043005,'But if thou wilt not send him, we will not go down: for the man said unto us, Ye shall not see my face, except your brother be with you.'); +INSERT INTO t1(docid,words) VALUES(1043006,'And Israel said, Wherefore dealt ye so ill with me, as to tell the man whether ye had yet a brother?'); +INSERT INTO t1(docid,words) VALUES(1043007,'And they said, The man asked us straitly of our state, and of our kindred, saying, Is your father yet alive? have ye another brother? and we told him according to the tenor of these words: could we certainly know that he would say, Bring your brother down?'); +INSERT INTO t1(docid,words) VALUES(1043008,'And Judah said unto Israel his father, Send the lad with me, and we will arise and go; that we may live, and not die, both we, and thou, and also our little ones.'); +INSERT INTO t1(docid,words) VALUES(1043009,'I will be surety for him; of my hand shalt thou require him: if I bring him not unto thee, and set him before thee, then let me bear the blame for ever:'); +INSERT INTO t1(docid,words) VALUES(1043010,'For except we had lingered, surely now we had returned this second time.'); +INSERT INTO t1(docid,words) VALUES(1043011,'And their father Israel said unto them, If it must be so now, do this; take of the best fruits in the land in your vessels, and carry down the man a present, a little balm, and a little honey, spices, and myrrh, nuts, and almonds:'); +INSERT INTO t1(docid,words) VALUES(1043012,'And take double money in your hand; and the money that was brought again in the mouth of your sacks, carry it again in your hand; peradventure it was an oversight:'); +INSERT INTO t1(docid,words) VALUES(1043013,'Take also your brother, and arise, go again unto the man:'); +INSERT INTO t1(docid,words) VALUES(1043014,'And God Almighty give you mercy before the man, that he may send away your other brother, and Benjamin. If I be bereaved of my children, I am bereaved.'); +INSERT INTO t1(docid,words) VALUES(1043015,'And the men took that present, and they took double money in their hand and Benjamin; and rose up, and went down to Egypt, and stood before Joseph.'); +INSERT INTO t1(docid,words) VALUES(1043016,'And when Joseph saw Benjamin with them, he said to the ruler of his house, Bring these men home, and slay, and make ready; for these men shall dine with me at noon.'); +INSERT INTO t1(docid,words) VALUES(1043017,'And the man did as Joseph bade; and the man brought the men into Joseph''s house.'); +INSERT INTO t1(docid,words) VALUES(1043018,'And the men were afraid, because they were brought into Joseph''s house; and they said, Because of the money that was returned in our sacks at the first time are we brought in; that he may seek occasion against us, and fall upon us, and take us for bondmen, and our asses.'); +INSERT INTO t1(docid,words) VALUES(1043019,'And they came near to the steward of Joseph''s house, and they communed with him at the door of the house,'); +INSERT INTO t1(docid,words) VALUES(1043020,'And said, O sir, we came indeed down at the first time to buy food:'); +INSERT INTO t1(docid,words) VALUES(1043021,'And it came to pass, when we came to the inn, that we opened our sacks, and, behold, every man''s money was in the mouth of his sack, our money in full weight: and we have brought it again in our hand.'); +INSERT INTO t1(docid,words) VALUES(1043022,'And other money have we brought down in our hands to buy food: we cannot tell who put our money in our sacks.'); +INSERT INTO t1(docid,words) VALUES(1043023,'And he said, Peace be to you, fear not: your God, and the God of your father, hath given you treasure in your sacks: I had your money. And he brought Simeon out unto them.'); +INSERT INTO t1(docid,words) VALUES(1043024,'And the man brought the men into Joseph''s house, and gave them water, and they washed their feet; and he gave their asses provender.'); +INSERT INTO t1(docid,words) VALUES(1043025,'And they made ready the present against Joseph came at noon: for they heard that they should eat bread there.'); +INSERT INTO t1(docid,words) VALUES(1043026,'And when Joseph came home, they brought him the present which was in their hand into the house, and bowed themselves to him to the earth.'); +INSERT INTO t1(docid,words) VALUES(1043027,'And he asked them of their welfare, and said, Is your father well, the old man of whom ye spake? Is he yet alive?'); +INSERT INTO t1(docid,words) VALUES(1043028,'And they answered, Thy servant our father is in good health, he is yet alive. And they bowed down their heads, and made obeisance.'); +INSERT INTO t1(docid,words) VALUES(1043029,'And he lifted up his eyes, and saw his brother Benjamin, his mother''s son, and said, Is this your younger brother, of whom ye spake unto me? And he said, God be gracious unto thee, my son.'); +INSERT INTO t1(docid,words) VALUES(1043030,'And Joseph made haste; for his bowels did yearn upon his brother: and he sought where to weep; and he entered into his chamber, and wept there.'); +INSERT INTO t1(docid,words) VALUES(1043031,'And he washed his face, and went out, and refrained himself, and said, Set on bread.'); +INSERT INTO t1(docid,words) VALUES(1043032,'And they set on for him by himself, and for them by themselves, and for the Egyptians, which did eat with him, by themselves: because the Egyptians might not eat bread with the Hebrews; for that is an abomination unto the Egyptians.'); +INSERT INTO t1(docid,words) VALUES(1043033,'And they sat before him, the firstborn according to his birthright, and the youngest according to his youth: and the men marvelled one at another.'); +INSERT INTO t1(docid,words) VALUES(1043034,'And he took and sent messes unto them from before him: but Benjamin''s mess was five times so much as any of their''s. And they drank, and were merry with him.'); +INSERT INTO t1(docid,words) VALUES(1044001,'And he commanded the steward of his house, saying, Fill the men''s sacks with food, as much as they can carry, and put every man''s money in his sack''s mouth.'); +INSERT INTO t1(docid,words) VALUES(1044002,'And put my cup, the silver cup, in the sack''s mouth of the youngest, and his corn money. And he did according to the word that Joseph had spoken.'); +INSERT INTO t1(docid,words) VALUES(1044003,'As soon as the morning was light, the men were sent away, they and their asses.'); +INSERT INTO t1(docid,words) VALUES(1044004,'And when they were gone out of the city, and not yet far off, Joseph said unto his steward, Up, follow after the men; and when thou dost overtake them, say unto them, Wherefore have ye rewarded evil for good?'); +INSERT INTO t1(docid,words) VALUES(1044005,'Is not this it in which my lord drinketh, and whereby indeed he divineth? ye have done evil in so doing.'); +INSERT INTO t1(docid,words) VALUES(1044006,'And he overtook them, and he spake unto them these same words.'); +INSERT INTO t1(docid,words) VALUES(1044007,'And they said unto him, Wherefore saith my lord these words? God forbid that thy servants should do according to this thing:'); +INSERT INTO t1(docid,words) VALUES(1044008,'Behold, the money, which we found in our sacks'' mouths, we brought again unto thee out of the land of Canaan: how then should we steal out of thy lord''s house silver or gold?'); +INSERT INTO t1(docid,words) VALUES(1044009,'With whomsoever of thy servants it be found, both let him die, and we also will be my lord''s bondmen.'); +INSERT INTO t1(docid,words) VALUES(1044010,'And he said, Now also let it be according unto your words: he with whom it is found shall be my servant; and ye shall be blameless.'); +INSERT INTO t1(docid,words) VALUES(1044011,'Then they speedily took down every man his sack to the ground, and opened every man his sack.'); +INSERT INTO t1(docid,words) VALUES(1044012,'And he searched, and began at the eldest, and left at the youngest: and the cup was found in Benjamin''s sack.'); +INSERT INTO t1(docid,words) VALUES(1044013,'Then they rent their clothes, and laded every man his ass, and returned to the city.'); +INSERT INTO t1(docid,words) VALUES(1044014,'And Judah and his brethren came to Joseph''s house; for he was yet there: and they fell before him on the ground.'); +INSERT INTO t1(docid,words) VALUES(1044015,'And Joseph said unto them, What deed is this that ye have done? wot ye not that such a man as I can certainly divine?'); +INSERT INTO t1(docid,words) VALUES(1044016,'And Judah said, What shall we say unto my lord? what shall we speak? or how shall we clear ourselves? God hath found out the iniquity of thy servants: behold, we are my lord''s servants, both we, and he also with whom the cup is found.'); +INSERT INTO t1(docid,words) VALUES(1044017,'And he said, God forbid that I should do so: but the man in whose hand the cup is found, he shall be my servant; and as for you, get you up in peace unto your father.'); +INSERT INTO t1(docid,words) VALUES(1044018,'Then Judah came near unto him, and said, Oh my lord, let thy servant, I pray thee, speak a word in my lord''s ears, and let not thine anger burn against thy servant: for thou art even as Pharaoh.'); +INSERT INTO t1(docid,words) VALUES(1044019,'My lord asked his servants, saying, Have ye a father, or a brother?'); +INSERT INTO t1(docid,words) VALUES(1044020,'And we said unto my lord, We have a father, an old man, and a child of his old age, a little one; and his brother is dead, and he alone is left of his mother, and his father loveth him.'); +INSERT INTO t1(docid,words) VALUES(1044021,'And thou saidst unto thy servants, Bring him down unto me, that I may set mine eyes upon him.'); +INSERT INTO t1(docid,words) VALUES(1044022,'And we said unto my lord, The lad cannot leave his father: for if he should leave his father, his father would die.'); +INSERT INTO t1(docid,words) VALUES(1044023,'And thou saidst unto thy servants, Except your youngest brother come down with you, ye shall see my face no more.'); +INSERT INTO t1(docid,words) VALUES(1044024,'And it came to pass when we came up unto thy servant my father, we told him the words of my lord.'); +INSERT INTO t1(docid,words) VALUES(1044025,'And our father said, Go again, and buy us a little food.'); +INSERT INTO t1(docid,words) VALUES(1044026,'And we said, We cannot go down: if our youngest brother be with us, then will we go down: for we may not see the man''s face, except our youngest brother be with us.'); +INSERT INTO t1(docid,words) VALUES(1044027,'And thy servant my father said unto us, Ye know that my wife bare me two sons:'); +INSERT INTO t1(docid,words) VALUES(1044028,'And the one went out from me, and I said, Surely he is torn in pieces; and I saw him not since:'); +INSERT INTO t1(docid,words) VALUES(1044029,'And if ye take this also from me, and mischief befall him, ye shall bring down my gray hairs with sorrow to the grave.'); +INSERT INTO t1(docid,words) VALUES(1044030,'Now therefore when I come to thy servant my father, and the lad be not with us; seeing that his life is bound up in the lad''s life;'); +INSERT INTO t1(docid,words) VALUES(1044031,'It shall come to pass, when he seeth that the lad is not with us, that he will die: and thy servants shall bring down the gray hairs of thy servant our father with sorrow to the grave.'); +INSERT INTO t1(docid,words) VALUES(1044032,'For thy servant became surety for the lad unto my father, saying, If I bring him not unto thee, then I shall bear the blame to my father for ever.'); +INSERT INTO t1(docid,words) VALUES(1044033,'Now therefore, I pray thee, let thy servant abide instead of the lad a bondman to my lord; and let the lad go up with his brethren.'); +INSERT INTO t1(docid,words) VALUES(1044034,'For how shall I go up to my father, and the lad be not with me? lest peradventure I see the evil that shall come on my father.'); +INSERT INTO t1(docid,words) VALUES(1045001,'Then Joseph could not refrain himself before all them that stood by him; and he cried, Cause every man to go out from me. And there stood no man with him, while Joseph made himself known unto his brethren.'); +INSERT INTO t1(docid,words) VALUES(1045002,'And he wept aloud: and the Egyptians and the house of Pharaoh heard.'); +INSERT INTO t1(docid,words) VALUES(1045003,'And Joseph said unto his brethren, I am Joseph; doth my father yet live? And his brethren could not answer him; for they were troubled at his presence.'); +INSERT INTO t1(docid,words) VALUES(1045004,'And Joseph said unto his brethren, Come near to me, I pray you. And they came near. And he said, I am Joseph your brother, whom ye sold into Egypt.'); +INSERT INTO t1(docid,words) VALUES(1045005,'Now therefore be not grieved, nor angry with yourselves, that ye sold me hither: for God did send me before you to preserve life.'); +INSERT INTO t1(docid,words) VALUES(1045006,'For these two years hath the famine been in the land: and yet there are five years, in the which there shall neither be earing nor harvest.'); +INSERT INTO t1(docid,words) VALUES(1045007,'And God sent me before you to preserve you a posterity in the earth, and to save your lives by a great deliverance.'); +INSERT INTO t1(docid,words) VALUES(1045008,'So now it was not you that sent me hither, but God: and he hath made me a father to Pharaoh, and lord of all his house, and a ruler throughout all the land of Egypt.'); +INSERT INTO t1(docid,words) VALUES(1045009,'Haste ye, and go up to my father, and say unto him, Thus saith thy son Joseph, God hath made me lord of all Egypt: come down unto me, tarry not:'); +INSERT INTO t1(docid,words) VALUES(1045010,'And thou shalt dwell in the land of Goshen, and thou shalt be near unto me, thou, and thy children, and thy children''s children, and thy flocks, and thy herds, and all that thou hast:'); +INSERT INTO t1(docid,words) VALUES(1045011,'And there will I nourish thee; for yet there are five years of famine; lest thou, and thy household, and all that thou hast, come to poverty.'); +INSERT INTO t1(docid,words) VALUES(1045012,'And, behold, your eyes see, and the eyes of my brother Benjamin, that it is my mouth that speaketh unto you.'); +INSERT INTO t1(docid,words) VALUES(1045013,'And ye shall tell my father of all my glory in Egypt, and of all that ye have seen; and ye shall haste and bring down my father hither.'); +INSERT INTO t1(docid,words) VALUES(1045014,'And he fell upon his brother Benjamin''s neck, and wept; and Benjamin wept upon his neck.'); +INSERT INTO t1(docid,words) VALUES(1045015,'Moreover he kissed all his brethren, and wept upon them: and after that his brethren talked with him.'); +INSERT INTO t1(docid,words) VALUES(1045016,'And the fame thereof was heard in Pharaoh''s house, saying, Joseph''s brethren are come: and it pleased Pharaoh well, and his servants.'); +INSERT INTO t1(docid,words) VALUES(1045017,'And Pharaoh said unto Joseph, Say unto thy brethren, This do ye; lade your beasts, and go, get you unto the land of Canaan;'); +INSERT INTO t1(docid,words) VALUES(1045018,'And take your father and your households, and come unto me: and I will give you the good of the land of Egypt, and ye shall eat the fat of the land.'); +INSERT INTO t1(docid,words) VALUES(1045019,'Now thou art commanded, this do ye; take you wagons out of the land of Egypt for your little ones, and for your wives, and bring your father, and come.'); +INSERT INTO t1(docid,words) VALUES(1045020,'Also regard not your stuff; for the good of all the land of Egypt is your''s.'); +INSERT INTO t1(docid,words) VALUES(1045021,'And the children of Israel did so: and Joseph gave them wagons, according to the commandment of Pharaoh, and gave them provision for the way.'); +INSERT INTO t1(docid,words) VALUES(1045022,'To all of them he gave each man changes of raiment; but to Benjamin he gave three hundred pieces of silver, and five changes of raiment.'); +INSERT INTO t1(docid,words) VALUES(1045023,'And to his father he sent after this manner; ten asses laden with the good things of Egypt, and ten she asses laden with corn and bread and meat for his father by the way.'); +INSERT INTO t1(docid,words) VALUES(1045024,'So he sent his brethren away, and they departed: and he said unto them, See that ye fall not out by the way.'); +INSERT INTO t1(docid,words) VALUES(1045025,'And they went up out of Egypt, and came into the land of Canaan unto Jacob their father,'); +INSERT INTO t1(docid,words) VALUES(1045026,'And told him, saying, Joseph is yet alive, and he is governor over all the land of Egypt. And Jacob''s heart fainted, for he believed them not.'); +INSERT INTO t1(docid,words) VALUES(1045027,'And they told him all the words of Joseph, which he had said unto them: and when he saw the wagons which Joseph had sent to carry him, the spirit of Jacob their father revived:'); +INSERT INTO t1(docid,words) VALUES(1045028,'And Israel said, It is enough; Joseph my son is yet alive: I will go and see him before I die.'); +INSERT INTO t1(docid,words) VALUES(1046001,'And Israel took his journey with all that he had, and came to Beersheba, and offered sacrifices unto the God of his father Isaac.'); +INSERT INTO t1(docid,words) VALUES(1046002,'And God spake unto Israel in the visions of the night, and said, Jacob, Jacob. And he said, Here am I.'); +INSERT INTO t1(docid,words) VALUES(1046003,'And he said, I am God, the God of thy father: fear not to go down into Egypt; for I will there make of thee a great nation:'); +INSERT INTO t1(docid,words) VALUES(1046004,'I will go down with thee into Egypt; and I will also surely bring thee up again: and Joseph shall put his hand upon thine eyes.'); +INSERT INTO t1(docid,words) VALUES(1046005,'And Jacob rose up from Beersheba: and the sons of Israel carried Jacob their father, and their little ones, and their wives, in the wagons which Pharaoh had sent to carry him.'); +INSERT INTO t1(docid,words) VALUES(1046006,'And they took their cattle, and their goods, which they had gotten in the land of Canaan, and came into Egypt, Jacob, and all his seed with him:'); +INSERT INTO t1(docid,words) VALUES(1046007,'His sons, and his sons'' sons with him, his daughters, and his sons'' daughters, and all his seed brought he with him into Egypt.'); +INSERT INTO t1(docid,words) VALUES(1046008,'And these are the names of the children of Israel, which came into Egypt, Jacob and his sons: Reuben, Jacob''s firstborn.'); +INSERT INTO t1(docid,words) VALUES(1046009,'And the sons of Reuben; Hanoch, and Phallu, and Hezron, and Carmi.'); +INSERT INTO t1(docid,words) VALUES(1046010,'And the sons of Simeon; Jemuel, and Jamin, and Ohad, and Jachin, and Zohar, and Shaul the son of a Canaanitish woman.'); +INSERT INTO t1(docid,words) VALUES(1046011,'And the sons of Levi; Gershon, Kohath, and Merari.'); +INSERT INTO t1(docid,words) VALUES(1046012,'And the sons of Judah; Er, and Onan, and Shelah, and Pharez, and Zarah: but Er and Onan died in the land of Canaan. And the sons of Pharez were Hezron and Hamul.'); +INSERT INTO t1(docid,words) VALUES(1046013,'And the sons of Issachar; Tola, and Phuvah, and Job, and Shimron.'); +INSERT INTO t1(docid,words) VALUES(1046014,'And the sons of Zebulun; Sered, and Elon, and Jahleel.'); +INSERT INTO t1(docid,words) VALUES(1046015,'These be the sons of Leah, which she bare unto Jacob in Padanaram, with his daughter Dinah: all the souls of his sons and his daughters were thirty and three.'); +INSERT INTO t1(docid,words) VALUES(1046016,'And the sons of Gad; Ziphion, and Haggi, Shuni, and Ezbon, Eri, and Arodi, and Areli.'); +INSERT INTO t1(docid,words) VALUES(1046017,'And the sons of Asher; Jimnah, and Ishuah, and Isui, and Beriah, and Serah their sister: and the sons of Beriah; Heber, and Malchiel.'); +INSERT INTO t1(docid,words) VALUES(1046018,'These are the sons of Zilpah, whom Laban gave to Leah his daughter, and these she bare unto Jacob, even sixteen souls.'); +INSERT INTO t1(docid,words) VALUES(1046019,'The sons of Rachel Jacob''s wife; Joseph, and Benjamin.'); +INSERT INTO t1(docid,words) VALUES(1046020,'And unto Joseph in the land of Egypt were born Manasseh and Ephraim, which Asenath the daughter of Potipherah priest of On bare unto him.'); +INSERT INTO t1(docid,words) VALUES(1046021,'And the sons of Benjamin were Belah, and Becher, and Ashbel, Gera, and Naaman, Ehi, and Rosh, Muppim, and Huppim, and Ard.'); +INSERT INTO t1(docid,words) VALUES(1046022,'These are the sons of Rachel, which were born to Jacob: all the souls were fourteen.'); +INSERT INTO t1(docid,words) VALUES(1046023,'And the sons of Dan; Hushim.'); +INSERT INTO t1(docid,words) VALUES(1046024,'And the sons of Naphtali; Jahzeel, and Guni, and Jezer, and Shillem.'); +INSERT INTO t1(docid,words) VALUES(1046025,'These are the sons of Bilhah, which Laban gave unto Rachel his daughter, and she bare these unto Jacob: all the souls were seven.'); +INSERT INTO t1(docid,words) VALUES(1046026,'All the souls that came with Jacob into Egypt, which came out of his loins, besides Jacob''s sons'' wives, all the souls were threescore and six;'); +INSERT INTO t1(docid,words) VALUES(1046027,'And the sons of Joseph, which were born him in Egypt, were two souls: all the souls of the house of Jacob, which came into Egypt, were threescore and ten.'); +INSERT INTO t1(docid,words) VALUES(1046028,'And he sent Judah before him unto Joseph, to direct his face unto Goshen; and they came into the land of Goshen.'); +INSERT INTO t1(docid,words) VALUES(1046029,'And Joseph made ready his chariot, and went up to meet Israel his father, to Goshen, and presented himself unto him; and he fell on his neck, and wept on his neck a good while.'); +INSERT INTO t1(docid,words) VALUES(1046030,'And Israel said unto Joseph, Now let me die, since I have seen thy face, because thou art yet alive.'); +INSERT INTO t1(docid,words) VALUES(1046031,'And Joseph said unto his brethren, and unto his father''s house, I will go up, and shew Pharaoh, and say unto him, My brethren, and my father''s house, which were in the land of Canaan, are come unto me;'); +INSERT INTO t1(docid,words) VALUES(1046032,'And the men are shepherds, for their trade hath been to feed cattle; and they have brought their flocks, and their herds, and all that they have.'); +INSERT INTO t1(docid,words) VALUES(1046033,'And it shall come to pass, when Pharaoh shall call you, and shall say, What is your occupation?'); +INSERT INTO t1(docid,words) VALUES(1046034,'That ye shall say, Thy servants'' trade hath been about cattle from our youth even until now, both we, and also our fathers: that ye may dwell in the land of Goshen; for every shepherd is an abomination unto the Egyptians.'); +INSERT INTO t1(docid,words) VALUES(1047001,'Then Joseph came and told Pharaoh, and said, My father and my brethren, and their flocks, and their herds, and all that they have, are come out of the land of Canaan; and, behold, they are in the land of Goshen.'); +INSERT INTO t1(docid,words) VALUES(1047002,'And he took some of his brethren, even five men, and presented them unto Pharaoh.'); +INSERT INTO t1(docid,words) VALUES(1047003,'And Pharaoh said unto his brethren, What is your occupation? And they said unto Pharaoh, Thy servants are shepherds, both we, and also our fathers.'); +INSERT INTO t1(docid,words) VALUES(1047004,'They said morever unto Pharaoh, For to sojourn in the land are we come; for thy servants have no pasture for their flocks; for the famine is sore in the land of Canaan: now therefore, we pray thee, let thy servants dwell in the land of Goshen.'); +INSERT INTO t1(docid,words) VALUES(1047005,'And Pharaoh spake unto Joseph, saying, Thy father and thy brethren are come unto thee:'); +INSERT INTO t1(docid,words) VALUES(1047006,'The land of Egypt is before thee; in the best of the land make thy father and brethren to dwell; in the land of Goshen let them dwell: and if thou knowest any men of activity among them, then make them rulers over my cattle.'); +INSERT INTO t1(docid,words) VALUES(1047007,'And Joseph brought in Jacob his father, and set him before Pharaoh: and Jacob blessed Pharaoh.'); +INSERT INTO t1(docid,words) VALUES(1047008,'And Pharaoh said unto Jacob, How old art thou?'); +INSERT INTO t1(docid,words) VALUES(1047009,'And Jacob said unto Pharaoh, The days of the years of my pilgrimage are an hundred and thirty years: few and evil have the days of the years of my life been, and have not attained unto the days of the years of the life of my fathers in the days of their pilgrimage.'); +INSERT INTO t1(docid,words) VALUES(1047010,'And Jacob blessed Pharaoh, and went out from before Pharaoh.'); +INSERT INTO t1(docid,words) VALUES(1047011,'And Joseph placed his father and his brethren, and gave them a possession in the land of Egypt, in the best of the land, in the land of Rameses, as Pharaoh had commanded.'); +INSERT INTO t1(docid,words) VALUES(1047012,'And Joseph nourished his father, and his brethren, and all his father''s household, with bread, according to their families.'); +INSERT INTO t1(docid,words) VALUES(1047013,'And there was no bread in all the land; for the famine was very sore, so that the land of Egypt and all the land of Canaan fainted by reason of the famine.'); +INSERT INTO t1(docid,words) VALUES(1047014,'And Joseph gathered up all the money that was found in the land of Egypt, and in the land of Canaan, for the corn which they bought: and Joseph brought the money into Pharaoh''s house.'); +INSERT INTO t1(docid,words) VALUES(1047015,'And when money failed in the land of Egypt, and in the land of Canaan, all the Egyptians came unto Joseph, and said, Give us bread: for why should we die in thy presence? for the money faileth.'); +INSERT INTO t1(docid,words) VALUES(1047016,'And Joseph said, Give your cattle; and I will give you for your cattle, if money fail.'); +INSERT INTO t1(docid,words) VALUES(1047017,'And they brought their cattle unto Joseph: and Joseph gave them bread in exchange for horses, and for the flocks, and for the cattle of the herds, and for the asses: and he fed them with bread for all their cattle for that year.'); +INSERT INTO t1(docid,words) VALUES(1047018,'When that year was ended, they came unto him the second year, and said unto him, We will not hide it from my lord, how that our money is spent; my lord also hath our herds of cattle; there is not ought left in the sight of my lord, but our bodies, and our lands:'); +INSERT INTO t1(docid,words) VALUES(1047019,'Wherefore shall we die before thine eyes, both we and our land? buy us and our land for bread, and we and our land will be servants unto Pharaoh: and give us seed, that we may live, and not die, that the land be not desolate.'); +INSERT INTO t1(docid,words) VALUES(1047020,'And Joseph bought all the land of Egypt for Pharaoh; for the Egyptians sold every man his field, because the famine prevailed over them: so the land became Pharaoh''s.'); +INSERT INTO t1(docid,words) VALUES(1047021,'And as for the people, he removed them to cities from one end of the borders of Egypt even to the other end thereof.'); +INSERT INTO t1(docid,words) VALUES(1047022,'Only the land of the priests bought he not; for the priests had a portion assigned them of Pharaoh, and did eat their portion which Pharaoh gave them: wherefore they sold not their lands.'); +INSERT INTO t1(docid,words) VALUES(1047023,'Then Joseph said unto the people, Behold, I have bought you this day and your land for Pharaoh: lo, here is seed for you, and ye shall sow the land.'); +INSERT INTO t1(docid,words) VALUES(1047024,'And it shall come to pass in the increase, that ye shall give the fifth part unto Pharaoh, and four parts shall be your own, for seed of the field, and for your food, and for them of your households, and for food for your little ones.'); +INSERT INTO t1(docid,words) VALUES(1047025,'And they said, Thou hast saved our lives: let us find grace in the sight of my lord, and we will be Pharaoh''s servants.'); +INSERT INTO t1(docid,words) VALUES(1047026,'And Joseph made it a law over the land of Egypt unto this day, that Pharaoh should have the fifth part, except the land of the priests only, which became not Pharaoh''s.'); +INSERT INTO t1(docid,words) VALUES(1047027,'And Israel dwelt in the land of Egypt, in the country of Goshen; and they had possessions therein, and grew, and multiplied exceedingly.'); +INSERT INTO t1(docid,words) VALUES(1047028,'And Jacob lived in the land of Egypt seventeen years: so the whole age of Jacob was an hundred forty and seven years.'); +INSERT INTO t1(docid,words) VALUES(1047029,'And the time drew nigh that Israel must die: and he called his son Joseph, and said unto him, If now I have found grace in thy sight, put, I pray thee, thy hand under my thigh, and deal kindly and truly with me; bury me not, I pray thee, in Egypt:'); +INSERT INTO t1(docid,words) VALUES(1047030,'But I will lie with my fathers, and thou shalt carry me out of Egypt, and bury me in their buryingplace. And he said, I will do as thou hast said.'); +INSERT INTO t1(docid,words) VALUES(1047031,'And he said, Swear unto me. And he sware unto him. And Israel bowed himself upon the bed''s head.'); +INSERT INTO t1(docid,words) VALUES(1048001,'And it came to pass after these things, that one told Joseph, Behold, thy father is sick: and he took with him his two sons, Manasseh and Ephraim.'); +INSERT INTO t1(docid,words) VALUES(1048002,'And one told Jacob, and said, Behold, thy son Joseph cometh unto thee: and Israel strengthened himself, and sat upon the bed.'); +INSERT INTO t1(docid,words) VALUES(1048003,'And Jacob said unto Joseph, God Almighty appeared unto me at Luz in the land of Canaan, and blessed me,'); +INSERT INTO t1(docid,words) VALUES(1048004,'And said unto me, Behold, I will make thee fruitful, and multiply thee, and I will make of thee a multitude of people; and will give this land to thy seed after thee for an everlasting possession.'); +INSERT INTO t1(docid,words) VALUES(1048005,'And now thy two sons, Ephraim and Manasseh, which were born unto thee in the land of Egypt before I came unto thee into Egypt, are mine; as Reuben and Simeon, they shall be mine.'); +INSERT INTO t1(docid,words) VALUES(1048006,'And thy issue, which thou begettest after them, shall be thine, and shall be called after the name of their brethren in their inheritance.'); +INSERT INTO t1(docid,words) VALUES(1048007,'And as for me, when I came from Padan, Rachel died by me in the land of Canaan in the way, when yet there was but a little way to come unto Ephrath: and I buried her there in the way of Ephrath; the same is Bethlehem.'); +INSERT INTO t1(docid,words) VALUES(1048008,'And Israel beheld Joseph''s sons, and said, Who are these?'); +INSERT INTO t1(docid,words) VALUES(1048009,'And Joseph said unto his father, They are my sons, whom God hath given me in this place. And he said, Bring them, I pray thee, unto me, and I will bless them.'); +INSERT INTO t1(docid,words) VALUES(1048010,'Now the eyes of Israel were dim for age, so that he could not see. And he brought them near unto him; and he kissed them, and embraced them.'); +INSERT INTO t1(docid,words) VALUES(1048011,'And Israel said unto Joseph, I had not thought to see thy face: and, lo, God hath shewed me also thy seed.'); +INSERT INTO t1(docid,words) VALUES(1048012,'And Joseph brought them out from between his knees, and he bowed himself with his face to the earth.'); +INSERT INTO t1(docid,words) VALUES(1048013,'And Joseph took them both, Ephraim in his right hand toward Israel''s left hand, and Manasseh in his left hand toward Israel''s right hand, and brought them near unto him.'); +INSERT INTO t1(docid,words) VALUES(1048014,'And Israel stretched out his right hand, and laid it upon Ephraim''s head, who was the younger, and his left hand upon Manasseh''s head, guiding his hands wittingly; for Manasseh was the firstborn.'); +INSERT INTO t1(docid,words) VALUES(1048015,'And he blessed Joseph, and said, God, before whom my fathers Abraham and Isaac did walk, the God which fed me all my life long unto this day,'); +INSERT INTO t1(docid,words) VALUES(1048016,'The Angel which redeemed me from all evil, bless the lads; and let my name be named on them, and the name of my fathers Abraham and Isaac; and let them grow into a multitude in the midst of the earth.'); +INSERT INTO t1(docid,words) VALUES(1048017,'And when Joseph saw that his father laid his right hand upon the head of Ephraim, it displeased him: and he held up his father''s hand, to remove it from Ephraim''s head unto Manasseh''s head.'); +INSERT INTO t1(docid,words) VALUES(1048018,'And Joseph said unto his father, Not so, my father: for this is the firstborn; put thy right hand upon his head.'); +INSERT INTO t1(docid,words) VALUES(1048019,'And his father refused, and said, I know it, my son, I know it: he also shall become a people, and he also shall be great: but truly his younger brother shall be greater than he, and his seed shall become a multitude of nations.'); +INSERT INTO t1(docid,words) VALUES(1048020,'And he blessed them that day, saying, In thee shall Israel bless, saying, God make thee as Ephraim and as Manasseh: and he set Ephraim before Manasseh.'); +INSERT INTO t1(docid,words) VALUES(1048021,'And Israel said unto Joseph, Behold, I die: but God shall be with you, and bring you again unto the land of your fathers.'); +INSERT INTO t1(docid,words) VALUES(1048022,'Moreover I have given to thee one portion above thy brethren, which I took out of the hand of the Amorite with my sword and with my bow.'); +INSERT INTO t1(docid,words) VALUES(1049001,'And Jacob called unto his sons, and said, Gather yourselves together, that I may tell you that which shall befall you in the last days.'); +INSERT INTO t1(docid,words) VALUES(1049002,'Gather yourselves together, and hear, ye sons of Jacob; and hearken unto Israel your father.'); +INSERT INTO t1(docid,words) VALUES(1049003,'Reuben, thou art my firstborn, my might, and the beginning of my strength, the excellency of dignity, and the excellency of power:'); +INSERT INTO t1(docid,words) VALUES(1049004,'Unstable as water, thou shalt not excel; because thou wentest up to thy father''s bed; then defiledst thou it: he went up to my couch.'); +INSERT INTO t1(docid,words) VALUES(1049005,'Simeon and Levi are brethren; instruments of cruelty are in their habitations.'); +INSERT INTO t1(docid,words) VALUES(1049006,'O my soul, come not thou into their secret; unto their assembly, mine honour, be not thou united: for in their anger they slew a man, and in their selfwill they digged down a wall.'); +INSERT INTO t1(docid,words) VALUES(1049007,'Cursed be their anger, for it was fierce; and their wrath, for it was cruel: I will divide them in Jacob, and scatter them in Israel.'); +INSERT INTO t1(docid,words) VALUES(1049008,'Judah, thou art he whom thy brethren shall praise: thy hand shall be in the neck of thine enemies; thy father''s children shall bow down before thee.'); +INSERT INTO t1(docid,words) VALUES(1049009,'Judah is a lion''s whelp: from the prey, my son, thou art gone up: he stooped down, he couched as a lion, and as an old lion; who shall rouse him up?'); +INSERT INTO t1(docid,words) VALUES(1049010,'The sceptre shall not depart from Judah, nor a lawgiver from between his feet, until Shiloh come; and unto him shall the gathering of the people be.'); +INSERT INTO t1(docid,words) VALUES(1049011,'Binding his foal unto the vine, and his ass''s colt unto the choice vine; he washed his garments in wine, and his clothes in the blood of grapes:'); +INSERT INTO t1(docid,words) VALUES(1049012,'His eyes shall be red with wine, and his teeth white with milk.'); +INSERT INTO t1(docid,words) VALUES(1049013,'Zebulun shall dwell at the haven of the sea; and he shall be for an haven of ships; and his border shall be unto Zidon.'); +INSERT INTO t1(docid,words) VALUES(1049014,'Issachar is a strong ass couching down between two burdens:'); +INSERT INTO t1(docid,words) VALUES(1049015,'And he saw that rest was good, and the land that it was pleasant; and bowed his shoulder to bear, and became a servant unto tribute.'); +INSERT INTO t1(docid,words) VALUES(1049016,'Dan shall judge his people, as one of the tribes of Israel.'); +INSERT INTO t1(docid,words) VALUES(1049017,'Dan shall be a serpent by the way, an adder in the path, that biteth the horse heels, so that his rider shall fall backward.'); +INSERT INTO t1(docid,words) VALUES(1049018,'I have waited for thy salvation, O LORD.'); +INSERT INTO t1(docid,words) VALUES(1049019,'Gad, a troop shall overcome him: but he shall overcome at the last.'); +INSERT INTO t1(docid,words) VALUES(1049020,'Out of Asher his bread shall be fat, and he shall yield royal dainties.'); +INSERT INTO t1(docid,words) VALUES(1049021,'Naphtali is a hind let loose: he giveth goodly words.'); +INSERT INTO t1(docid,words) VALUES(1049022,'Joseph is a fruitful bough, even a fruitful bough by a well; whose branches run over the wall:'); +INSERT INTO t1(docid,words) VALUES(1049023,'The archers have sorely grieved him, and shot at him, and hated him:'); +INSERT INTO t1(docid,words) VALUES(1049024,'But his bow abode in strength, and the arms of his hands were made strong by the hands of the mighty God of Jacob; (from thence is the shepherd, the stone of Israel:)'); +INSERT INTO t1(docid,words) VALUES(1049025,'Even by the God of thy father, who shall help thee; and by the Almighty, who shall bless thee with blessings of heaven above, blessings of the deep that lieth under, blessings of the breasts, and of the womb:'); +INSERT INTO t1(docid,words) VALUES(1049026,'The blessings of thy father have prevailed above the blessings of my progenitors unto the utmost bound of the everlasting hills: they shall be on the head of Joseph, and on the crown of the head of him that was separate from his brethren.'); +INSERT INTO t1(docid,words) VALUES(1049027,'Benjamin shall ravin as a wolf: in the morning he shall devour the prey, and at night he shall divide the spoil.'); +INSERT INTO t1(docid,words) VALUES(1049028,'All these are the twelve tribes of Israel: and this is it that their father spake unto them, and blessed them; every one according to his blessing he blessed them.'); +INSERT INTO t1(docid,words) VALUES(1049029,'And he charged them, and said unto them, I am to be gathered unto my people: bury me with my fathers in the cave that is in the field of Ephron the Hittite,'); +INSERT INTO t1(docid,words) VALUES(1049030,'In the cave that is in the field of Machpelah, which is before Mamre, in the land of Canaan, which Abraham bought with the field of Ephron the Hittite for a possession of a buryingplace.'); +INSERT INTO t1(docid,words) VALUES(1049031,'There they buried Abraham and Sarah his wife; there they buried Isaac and Rebekah his wife; and there I buried Leah.'); +INSERT INTO t1(docid,words) VALUES(1049032,'The purchase of the field and of the cave that is therein was from the children of Heth.'); +INSERT INTO t1(docid,words) VALUES(1049033,'And when Jacob had made an end of commanding his sons, he gathered up his feet into the bed, and yielded up the ghost, and was gathered unto his people.'); +INSERT INTO t1(docid,words) VALUES(1050001,'And Joseph fell upon his father''s face, and wept upon him, and kissed him.'); +INSERT INTO t1(docid,words) VALUES(1050002,'And Joseph commanded his servants the physicians to embalm his father: and the physicians embalmed Israel.'); +INSERT INTO t1(docid,words) VALUES(1050003,'And forty days were fulfilled for him; for so are fulfilled the days of those which are embalmed: and the Egyptians mourned for him threescore and ten days.'); +INSERT INTO t1(docid,words) VALUES(1050004,'And when the days of his mourning were past, Joseph spake unto the house of Pharaoh, saying, If now I have found grace in your eyes, speak, I pray you, in the ears of Pharaoh, saying,'); +INSERT INTO t1(docid,words) VALUES(1050005,'My father made me swear, saying, Lo, I die: in my grave which I have digged for me in the land of Canaan, there shalt thou bury me. Now therefore let me go up, I pray thee, and bury my father, and I will come again.'); +INSERT INTO t1(docid,words) VALUES(1050006,'And Pharaoh said, Go up, and bury thy father, according as he made thee swear.'); +INSERT INTO t1(docid,words) VALUES(1050007,'And Joseph went up to bury his father: and with him went up all the servants of Pharaoh, the elders of his house, and all the elders of the land of Egypt,'); +INSERT INTO t1(docid,words) VALUES(1050008,'And all the house of Joseph, and his brethren, and his father''s house: only their little ones, and their flocks, and their herds, they left in the land of Goshen.'); +INSERT INTO t1(docid,words) VALUES(1050009,'And there went up with him both chariots and horsemen: and it was a very great company.'); +INSERT INTO t1(docid,words) VALUES(1050010,'And they came to the threshingfloor of Atad, which is beyond Jordan, and there they mourned with a great and very sore lamentation: and he made a mourning for his father seven days.'); +INSERT INTO t1(docid,words) VALUES(1050011,'And when the inhabitants of the land, the Canaanites, saw the mourning in the floor of Atad, they said, This is a grievous mourning to the Egyptians: wherefore the name of it was called Abelmizraim, which is beyond Jordan.'); +INSERT INTO t1(docid,words) VALUES(1050012,'And his sons did unto him according as he commanded them:'); +INSERT INTO t1(docid,words) VALUES(1050013,'For his sons carried him into the land of Canaan, and buried him in the cave of the field of Machpelah, which Abraham bought with the field for a possession of a buryingplace of Ephron the Hittite, before Mamre.'); +INSERT INTO t1(docid,words) VALUES(1050014,'And Joseph returned into Egypt, he, and his brethren, and all that went up with him to bury his father, after he had buried his father.'); +INSERT INTO t1(docid,words) VALUES(1050015,'And when Joseph''s brethren saw that their father was dead, they said, Joseph will peradventure hate us, and will certainly requite us all the evil which we did unto him.'); +INSERT INTO t1(docid,words) VALUES(1050016,'And they sent a messenger unto Joseph, saying, Thy father did command before he died, saying,'); +INSERT INTO t1(docid,words) VALUES(1050017,'So shall ye say unto Joseph, Forgive, I pray thee now, the trespass of thy brethren, and their sin; for they did unto thee evil: and now, we pray thee, forgive the trespass of the servants of the God of thy father. And Joseph wept when they spake unto him.'); +INSERT INTO t1(docid,words) VALUES(1050018,'And his brethren also went and fell down before his face; and they said, Behold, we be thy servants.'); +INSERT INTO t1(docid,words) VALUES(1050019,'And Joseph said unto them, Fear not: for am I in the place of God?'); +INSERT INTO t1(docid,words) VALUES(1050020,'But as for you, ye thought evil against me; but God meant it unto good, to bring to pass, as it is this day, to save much people alive.'); +INSERT INTO t1(docid,words) VALUES(1050021,'Now therefore fear ye not: I will nourish you, and your little ones. And he comforted them, and spake kindly unto them.'); +INSERT INTO t1(docid,words) VALUES(1050022,'And Joseph dwelt in Egypt, he, and his father''s house: and Joseph lived an hundred and ten years.'); +INSERT INTO t1(docid,words) VALUES(1050023,'And Joseph saw Ephraim''s children of the third generation: the children also of Machir the son of Manasseh were brought up upon Joseph''s knees.'); +INSERT INTO t1(docid,words) VALUES(1050024,'And Joseph said unto his brethren, I die: and God will surely visit you, and bring you out of this land unto the land which he sware to Abraham, to Isaac, and to Jacob.'); +INSERT INTO t1(docid,words) VALUES(1050025,'And Joseph took an oath of the children of Israel, saying, God will surely visit you, and ye shall carry up my bones from hence.'); +INSERT INTO t1(docid,words) VALUES(1050026,'So Joseph died, being an hundred and ten years old: and they embalmed him, and he was put in a coffin in Egypt.'); +COMMIT; +} +} diff --git a/test/hexlit.test b/test/hexlit.test new file mode 100644 index 0000000..10909e6 --- /dev/null +++ b/test/hexlit.test @@ -0,0 +1,114 @@ +# 2014-07-23 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests for hexadecimal literals + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +proc hexlit1 {tnum val ans} { + do_execsql_test hexlit-$tnum "SELECT $val" $ans +} + +hexlit1 100 0x0 0 +hexlit1 101 0x0000000000000000000000000000000000000000000001 1 +hexlit1 102 0x2 2 +hexlit1 103 0x4 4 +hexlit1 104 0x8 8 +hexlit1 105 0x00000000000000000000000000000000000000000000010 16 +hexlit1 103 0x20 32 +hexlit1 106 0x40 64 +hexlit1 107 0x80 128 +hexlit1 108 0x100 256 +hexlit1 109 0x200 512 +hexlit1 110 0X400 1024 +hexlit1 111 0x800 2048 +hexlit1 112 0x1000 4096 +hexlit1 113 0x2000 8192 +hexlit1 114 0x4000 16384 +hexlit1 115 0x8000 32768 +hexlit1 116 0x10000 65536 +hexlit1 117 0x20000 131072 +hexlit1 118 0x40000 262144 +hexlit1 119 0x80000 524288 +hexlit1 120 0x100000 1048576 +hexlit1 121 0x200000 2097152 +hexlit1 122 0x400000 4194304 +hexlit1 123 0x800000 8388608 +hexlit1 124 0x1000000 16777216 +hexlit1 125 0x2000000 33554432 +hexlit1 126 0x4000000 67108864 +hexlit1 127 0x8000000 134217728 +hexlit1 128 0x10000000 268435456 +hexlit1 129 0x20000000 536870912 +hexlit1 130 0x40000000 1073741824 +hexlit1 131 0x80000000 2147483648 +hexlit1 132 0x100000000 4294967296 +hexlit1 133 0x200000000 8589934592 +hexlit1 134 0x400000000 17179869184 +hexlit1 135 0x800000000 34359738368 +hexlit1 136 0x1000000000 68719476736 +hexlit1 137 0x2000000000 137438953472 +hexlit1 138 0x4000000000 274877906944 +hexlit1 139 0x8000000000 549755813888 +hexlit1 140 0x10000000000 1099511627776 +hexlit1 141 0x20000000000 2199023255552 +hexlit1 142 0x40000000000 4398046511104 +hexlit1 143 0x80000000000 8796093022208 +hexlit1 144 0x100000000000 17592186044416 +hexlit1 145 0x200000000000 35184372088832 +hexlit1 146 0x400000000000 70368744177664 +hexlit1 147 0x800000000000 140737488355328 +hexlit1 148 0x1000000000000 281474976710656 +hexlit1 149 0x2000000000000 562949953421312 +hexlit1 150 0x4000000000000 1125899906842624 +hexlit1 151 0x8000000000000 2251799813685248 +hexlit1 152 0x10000000000000 4503599627370496 +hexlit1 153 0x20000000000000 9007199254740992 +hexlit1 154 0x40000000000000 18014398509481984 +hexlit1 155 0x80000000000000 36028797018963968 +hexlit1 156 0x100000000000000 72057594037927936 +hexlit1 157 0x200000000000000 144115188075855872 +hexlit1 158 0x400000000000000 288230376151711744 +hexlit1 159 0x800000000000000 576460752303423488 +hexlit1 160 0X1000000000000000 1152921504606846976 +hexlit1 161 0x2000000000000000 2305843009213693952 +hexlit1 162 0X4000000000000000 4611686018427387904 +hexlit1 163 0x8000000000000000 -9223372036854775808 +hexlit1 164 0XFFFFFFFFFFFFFFFF -1 + +for {set n 1} {$n < 0x10} {incr n} { + hexlit1 200.$n.1 0X[format %03X $n] $n + hexlit1 200.$n.2 0x[format %03X $n] $n + hexlit1 200.$n.3 0X[format %03x $n] $n + hexlit1 200.$n.4 0x[format %03x $n] $n +} + +# String literals that look like hex do not get cast or coerced. +# +do_execsql_test hexlit-300 { + CREATE TABLE t1(x INT, y REAL); + INSERT INTO t1 VALUES('1234','4567'),('0x1234','0x4567'); + SELECT typeof(x), x, typeof(y), y, '#' FROM t1 ORDER BY rowid; +} {integer 1234 real 4567.0 # text 0x1234 text 0x4567 #} +do_execsql_test hexlit-301 { + SELECT CAST('0x1234' AS INTEGER); +} {0} + +# Oversized hex literals are rejected +# +do_catchsql_test hexlist-400 { + SELECT 0x10000000000000000; +} {1 {hex literal too big: 0x10000000000000000}} + + +finish_test diff --git a/test/hook.test b/test/hook.test index 6346cc7..de6fbdd 100644 --- a/test/hook.test +++ b/test/hook.test @@ -127,21 +127,52 @@ db2 close # depopulation of indices, to make sure the update-hook is not # invoked incorrectly. # +# EVIDENCE-OF: R-21999-45122 The sqlite3_update_hook() interface +# registers a callback function with the database connection identified +# by the first argument to be invoked whenever a row is updated, +# inserted or deleted in a rowid table. # Simple tests -do_test hook-4.1.1 { +do_test hook-4.1.1a { catchsql { DROP TABLE t1; } + unset -nocomplain ::update_hook + set ::update_hook {} + db update_hook [list lappend ::update_hook] + # + # EVIDENCE-OF: R-52223-27275 The update hook is not invoked when + # internal system tables are modified (i.e. sqlite_master and + # sqlite_sequence). + # execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + CREATE TABLE t1w(a INT PRIMARY KEY, b) WITHOUT ROWID; + } + set ::update_hook +} {} +do_test hook-4.1.1b { + execsql { INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); INSERT INTO t1 VALUES(3, 'three'); + INSERT INTO t1w SELECT * FROM t1; } - db update_hook [list lappend ::update_hook] } {} + +# EVIDENCE-OF: R-15506-57666 The second callback argument is one of +# SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE, depending on the +# operation that caused the callback to be invoked. +# +# EVIDENCE-OF: R-29213-61195 The third and fourth arguments to the +# callback contain pointers to the database and table name containing +# the affected row. +# +# EVIDENCE-OF: R-30809-57812 The final callback parameter is the rowid +# of the row. +# do_test hook-4.1.2 { + set ::update_hook {} execsql { INSERT INTO t1 VALUES(4, 'four'); DELETE FROM t1 WHERE b = 'two'; @@ -159,6 +190,23 @@ do_test hook-4.1.2 { DELETE main t1 4 \ ] +# EVIDENCE-OF: R-61808-14344 The sqlite3_update_hook() interface does +# not fire callbacks for changes to a WITHOUT ROWID table. +# +# EVIDENCE-OF: R-33257-44249 The update hook is not invoked when WITHOUT +# ROWID tables are modified. +# +do_test hook-4.1.2w { + set ::update_hook {} + execsql { + INSERT INTO t1w VALUES(4, 'four'); + DELETE FROM t1w WHERE b = 'two'; + UPDATE t1w SET b = '' WHERE a = 1 OR a = 3; + DELETE FROM t1w WHERE 1; -- Avoid the truncate optimization (for now) + } + set ::update_hook +} {} + ifcapable trigger { # Update hook is not invoked for changes to sqlite_master # diff --git a/test/in.test b/test/in.test index 3b23f04..515e598 100644 --- a/test/in.test +++ b/test/in.test @@ -332,7 +332,7 @@ do_test in-10.2 { catchsql { INSERT INTO t5 VALUES(4); } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t5}} # Ticket #1821 # diff --git a/test/in4.test b/test/in4.test index 470f4f0..a89961f 100644 --- a/test/in4.test +++ b/test/in4.test @@ -159,4 +159,181 @@ do_test in4-3.12 { execsql { SELECT * FROM t3 WHERE x IN (1, 2) AND y IN ()} } {} +# Tests for "... IN (?)" and "... NOT IN (?)". In other words, tests +# for when the RHS of IN is a single expression. This should work the +# same as the == and <> operators. +# +do_execsql_test in4-3.21 { + SELECT * FROM t3 WHERE x=10 AND y IN (10); +} {10 10 10} +do_execsql_test in4-3.22 { + SELECT * FROM t3 WHERE x IN (10) AND y=10; +} {10 10 10} +do_execsql_test in4-3.23 { + SELECT * FROM t3 WHERE x IN (10) AND y IN (10); +} {10 10 10} +do_execsql_test in4-3.24 { + SELECT * FROM t3 WHERE x=1 AND y NOT IN (10); +} {1 1 1} +do_execsql_test in4-3.25 { + SELECT * FROM t3 WHERE x NOT IN (10) AND y=1; +} {1 1 1} +do_execsql_test in4-3.26 { + SELECT * FROM t3 WHERE x NOT IN (10) AND y NOT IN (10); +} {1 1 1} + +# The query planner recognizes that "x IN (?)" only generates a +# single match and can use this information to optimize-out ORDER BY +# clauses. +# +do_execsql_test in4-3.31 { + DROP INDEX t3i1; + CREATE UNIQUE INDEX t3xy ON t3(x,y); + + SELECT *, '|' FROM t3 A, t3 B + WHERE A.x=10 AND A.y IN (10) + AND B.x=1 AND B.y IN (1); +} {10 10 10 1 1 1 |} +do_execsql_test in4-3.32 { + EXPLAIN QUERY PLAN + SELECT *, '|' FROM t3 A, t3 B + WHERE A.x=10 AND A.y IN (10) + AND B.x=1 AND B.y IN (1); +} {~/B-TREE/} ;# No separate sorting pass +do_execsql_test in4-3.33 { + SELECT *, '|' FROM t3 A, t3 B + WHERE A.x IN (10) AND A.y=10 + AND B.x IN (1) AND B.y=1; +} {10 10 10 1 1 1 |} +do_execsql_test in4-3.34 { + EXPLAIN QUERY PLAN + SELECT *, '|' FROM t3 A, t3 B + WHERE A.x IN (10) AND A.y=10 + AND B.x IN (1) AND B.y=1; +} {~/B-TREE/} ;# No separate sorting pass + +# An expression of the form "x IN (?,?)" creates an ephemeral table to +# hold the list of values on the RHS. But "x IN (?)" does not create +# an ephemeral table. +# +do_execsql_test in4-3.41 { + SELECT * FROM t3 WHERE x IN (10,11); +} {10 10 10} +do_execsql_test in4-3.42 { + EXPLAIN + SELECT * FROM t3 WHERE x IN (10,11); +} {/OpenEphemeral/} +do_execsql_test in4-3.43 { + SELECT * FROM t3 WHERE x IN (10); +} {10 10 10} +do_execsql_test in4-3.44 { + EXPLAIN + SELECT * FROM t3 WHERE x IN (10); +} {~/OpenEphemeral/} +do_execsql_test in4-3.45 { + SELECT * FROM t3 WHERE x NOT IN (10,11,99999); +} {1 1 1} +do_execsql_test in4-3.46 { + EXPLAIN + SELECT * FROM t3 WHERE x NOT IN (10,11,99999); +} {/OpenEphemeral/} +do_execsql_test in4-3.47 { + SELECT * FROM t3 WHERE x NOT IN (10); +} {1 1 1} +do_execsql_test in4-3.48 { + EXPLAIN + SELECT * FROM t3 WHERE x NOT IN (10); +} {~/OpenEphemeral/} + +# Make sure that when "x IN (?)" is converted into "x==?" that collating +# sequence and affinity computations do not get messed up. +# +do_execsql_test in4-4.1 { + CREATE TABLE t4a(a TEXT, b TEXT COLLATE nocase, c); + INSERT INTO t4a VALUES('ABC','abc',1); + INSERT INTO t4a VALUES('def','xyz',2); + INSERT INTO t4a VALUES('ghi','ghi',3); + SELECT c FROM t4a WHERE a=b ORDER BY c; +} {3} +do_execsql_test in4-4.2 { + SELECT c FROM t4a WHERE b=a ORDER BY c; +} {1 3} +do_execsql_test in4-4.3 { + SELECT c FROM t4a WHERE (a||'')=b ORDER BY c; +} {1 3} +do_execsql_test in4-4.4 { + SELECT c FROM t4a WHERE (a||'')=(b||'') ORDER BY c; +} {3} +do_execsql_test in4-4.5 { + SELECT c FROM t4a WHERE a IN (b) ORDER BY c; +} {3} +do_execsql_test in4-4.6 { + SELECT c FROM t4a WHERE (a||'') IN (b) ORDER BY c; +} {3} + + +do_execsql_test in4-4.11 { + CREATE TABLE t4b(a TEXT, b NUMERIC, c); + INSERT INTO t4b VALUES('1.0',1,4); + SELECT c FROM t4b WHERE a=b; +} {4} +do_execsql_test in4-4.12 { + SELECT c FROM t4b WHERE b=a; +} {4} +do_execsql_test in4-4.13 { + SELECT c FROM t4b WHERE +a=b; +} {4} +do_execsql_test in4-4.14 { + SELECT c FROM t4b WHERE a=+b; +} {} +do_execsql_test in4-4.15 { + SELECT c FROM t4b WHERE +b=a; +} {} +do_execsql_test in4-4.16 { + SELECT c FROM t4b WHERE b=+a; +} {4} +do_execsql_test in4-4.17 { + SELECT c FROM t4b WHERE a IN (b); +} {} +do_execsql_test in4-4.18 { + SELECT c FROM t4b WHERE b IN (a); +} {4} +do_execsql_test in4-4.19 { + SELECT c FROM t4b WHERE +b IN (a); +} {} + +do_execsql_test in4-5.1 { + CREATE TABLE t5(c INTEGER PRIMARY KEY, d TEXT COLLATE nocase); + INSERT INTO t5 VALUES(17, 'fuzz'); + SELECT 1 FROM t5 WHERE 'fuzz' IN (d); -- match + SELECT 2 FROM t5 WHERE 'FUZZ' IN (d); -- no match + SELECT 3 FROM t5 WHERE d IN ('fuzz'); -- match + SELECT 4 FROM t5 WHERE d IN ('FUZZ'); -- match +} {1 3 4} + +# An expression of the form "x IN (y)" can be used as "x=y" by the +# query planner when computing transitive constraints or to run the +# query using an index on y. +# +do_execsql_test in4-6.1 { + CREATE TABLE t6a(a INTEGER PRIMARY KEY, b); + INSERT INTO t6a VALUES(1,2),(3,4),(5,6); + CREATE TABLE t6b(c INTEGER PRIMARY KEY, d); + INSERT INTO t6b VALUES(4,44),(5,55),(6,66); + + SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c); +} {3 4 4 44} +do_execsql_test in4-6.1-eqp { + EXPLAIN QUERY PLAN + SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c); +} {~/SCAN/} +do_execsql_test in4-6.2 { + SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b); +} {3 4 4 44} +do_execsql_test in4-6.2-eqp { + EXPLAIN QUERY PLAN + SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b); +} {~/SCAN/} + + finish_test diff --git a/test/incrblob2.test b/test/incrblob2.test index 9046de2..a8f40f0 100644 --- a/test/incrblob2.test +++ b/test/incrblob2.test @@ -397,16 +397,16 @@ do_test incrblob2-8.4 { } {cccccccccccccccccccc} do_test incrblob2-8.5 { catchsql {UPDATE t3 SET a = 6 WHERE a > 3} -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: t3.a}} do_test incrblob2-8.6 { catchsql {UPDATE t3 SET a = 6 WHERE a > 3} -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: t3.a}} do_test incrblob2-8.7 { sqlite3_blob_read $h 0 20 } {cccccccccccccccccccc} do_test incrblob2-8.8 { catchsql {UPDATE t3 SET a = 6 WHERE a = 3 OR a = 5} -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: t3.a}} do_test incrblob2-8.9 { set rc [catch {sqlite3_blob_read $h 0 20} msg] list $rc $msg diff --git a/test/incrblob3.test b/test/incrblob3.test index 4c49f15..5f2e860 100644 --- a/test/incrblob3.test +++ b/test/incrblob3.test @@ -269,4 +269,3 @@ db close tvfs delete finish_test - diff --git a/test/incrblob4.test b/test/incrblob4.test index a96356b..a92e373 100644 --- a/test/incrblob4.test +++ b/test/incrblob4.test @@ -87,4 +87,3 @@ do_test 3.3 { } {} finish_test - diff --git a/test/incrblob_err.test b/test/incrblob_err.test index 35d37fe..a08bea3 100644 --- a/test/incrblob_err.test +++ b/test/incrblob_err.test @@ -14,6 +14,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set ::testprefix incrblob_err ifcapable {!incrblob || !memdebug || !tclvar} { finish_test diff --git a/test/incrblobfault.test b/test/incrblobfault.test index d125471..0c1d93d 100644 --- a/test/incrblobfault.test +++ b/test/incrblobfault.test @@ -67,4 +67,3 @@ do_faultsim_test 3 -prep { } finish_test - diff --git a/test/incrvacuum3.test b/test/incrvacuum3.test index f01dc10..e901bfe 100644 --- a/test/incrvacuum3.test +++ b/test/incrvacuum3.test @@ -151,4 +151,3 @@ foreach {T jrnl_mode} { } finish_test - diff --git a/test/index.test b/test/index.test index 790bed9..59c0ea6 100644 --- a/test/index.test +++ b/test/index.test @@ -666,7 +666,7 @@ ifcapable conflict { BEGIN; INSERT INTO t7 VALUES(1); } - } {1 {column a is not unique}} + } {1 {UNIQUE constraint failed: t7.a}} do_test index-19.3 { catchsql { BEGIN; @@ -676,7 +676,7 @@ ifcapable conflict { catchsql { INSERT INTO t8 VALUES(1); } - } {1 {column a is not unique}} + } {1 {UNIQUE constraint failed: t8.a}} do_test index-19.5 { catchsql { BEGIN; @@ -715,6 +715,23 @@ do_test index-20.2 { DROP INDEX "t6i1"; } } {} + +# Try to create a TEMP index on a non-TEMP table. */ +# +do_test index-21.1 { + catchsql { + CREATE INDEX temp.i21 ON t6(c); + } +} {1 {cannot create a TEMP index on non-TEMP table "t6"}} +do_test index-21.2 { + catchsql { + CREATE TEMP TABLE t6(x); + INSERT INTO temp.t6 values(1),(5),(9); + CREATE INDEX temp.i21 ON t6(x); + SELECT x FROM t6 ORDER BY x DESC; + } +} {0 {9 5 1}} + finish_test diff --git a/test/index3.test b/test/index3.test index 161ddec..a9f9b7a 100644 --- a/test/index3.test +++ b/test/index3.test @@ -34,7 +34,7 @@ do_test index3-1.2 { BEGIN; CREATE UNIQUE INDEX i1 ON t1(a); } -} {1 {indexed columns are not unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test index3-1.3 { catchsql COMMIT; } {0 {}} diff --git a/test/index4.test b/test/index4.test index 018ed74..4fbfa52 100644 --- a/test/index4.test +++ b/test/index4.test @@ -120,7 +120,7 @@ do_execsql_test 2.1 { } do_catchsql_test 2.2 { CREATE UNIQUE INDEX i3 ON t2(x); -} {1 {indexed columns are not unique}} +} {1 {UNIQUE constraint failed: t2.x}} finish_test diff --git a/test/index6.test b/test/index6.test new file mode 100644 index 0000000..68bdd06 --- /dev/null +++ b/test/index6.test @@ -0,0 +1,271 @@ +# 2013-07-31 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Test cases for partial indices +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !vtab { + finish_test + return +} + +load_static_extension db wholenumber; +do_test index6-1.1 { + # Able to parse and manage partial indices + execsql { + CREATE TABLE t1(a,b,c); + CREATE INDEX t1a ON t1(a) WHERE a IS NOT NULL; + CREATE INDEX t1b ON t1(b) WHERE b>10; + CREATE VIRTUAL TABLE nums USING wholenumber; + INSERT INTO t1(a,b,c) + SELECT CASE WHEN value%3!=0 THEN value END, value, value + FROM nums WHERE value<=20; + SELECT count(a), count(b) FROM t1; + PRAGMA integrity_check; + } +} {14 20 ok} + +# Make sure the count(*) optimization works correctly with +# partial indices. Ticket [a5c8ed66cae16243be6] 2013-10-03. +# +do_execsql_test index6-1.1.1 { + SELECT count(*) FROM t1; +} {20} + +# Error conditions during parsing... +# +do_test index6-1.2 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE x IS NOT NULL; + } +} {1 {no such column: x}} +do_test index6-1.3 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE EXISTS(SELECT * FROM t1); + } +} {1 {subqueries prohibited in partial index WHERE clauses}} +do_test index6-1.4 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE a!=?1; + } +} {1 {parameters prohibited in partial index WHERE clauses}} +do_test index6-1.5 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE a!=random(); + } +} {1 {functions prohibited in partial index WHERE clauses}} +do_test index6-1.6 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE a NOT LIKE 'abc%'; + } +} {1 {functions prohibited in partial index WHERE clauses}} + +do_test index6-1.10 { + execsql { + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {{} 20 t1a {14 1} t1b {10 1} ok} + +# STAT1 shows the partial indices have a reduced number of +# rows. +# +do_test index6-1.11 { + execsql { + UPDATE t1 SET a=b; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {{} 20 t1a {20 1} t1b {10 1} ok} + +do_test index6-1.11 { + execsql { + UPDATE t1 SET a=NULL WHERE b%3!=0; + UPDATE t1 SET b=b+100; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {{} 20 t1a {6 1} t1b {20 1} ok} + +do_test index6-1.12 { + execsql { + UPDATE t1 SET a=CASE WHEN b%3!=0 THEN b END; + UPDATE t1 SET b=b-100; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {{} 20 t1a {13 1} t1b {10 1} ok} + +do_test index6-1.13 { + execsql { + DELETE FROM t1 WHERE b BETWEEN 8 AND 12; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {{} 15 t1a {10 1} t1b {8 1} ok} + +do_test index6-1.14 { + execsql { + REINDEX; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {{} 15 t1a {10 1} t1b {8 1} ok} + +do_test index6-1.15 { + execsql { + CREATE INDEX t1c ON t1(c); + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {t1a {10 1} t1b {8 1} t1c {15 1} ok} + +# Queries use partial indices as appropriate times. +# +do_test index6-2.1 { + execsql { + CREATE TABLE t2(a,b); + INSERT INTO t2(a,b) SELECT value, value FROM nums WHERE value<1000; + UPDATE t2 SET a=NULL WHERE b%2==0; + CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL; + SELECT count(*) FROM t2 WHERE a IS NOT NULL; + } +} {500} +do_test index6-2.2 { + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t2 WHERE a=5; + } +} {/.* TABLE t2 USING INDEX t2a1 .*/} +ifcapable stat4||stat3 { + execsql ANALYZE + do_test index6-2.3stat4 { + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t2 WHERE a IS NOT NULL; + } + } {/.* TABLE t2 USING INDEX t2a1 .*/} +} else { + do_test index6-2.3stat4 { + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t2 WHERE a IS NOT NULL AND a>0; + } + } {/.* TABLE t2 USING INDEX t2a1 .*/} +} +do_test index6-2.4 { + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t2 WHERE a IS NULL; + } +} {~/.*INDEX t2a1.*/} + +do_execsql_test index6-2.101 { + DROP INDEX t2a1; + UPDATE t2 SET a=b, b=b+10000; + SELECT b FROM t2 WHERE a=15; +} {10015} +do_execsql_test index6-2.102 { + CREATE INDEX t2a2 ON t2(a) WHERE a<100 OR a>200; + SELECT b FROM t2 WHERE a=15; + PRAGMA integrity_check; +} {10015 ok} +do_execsql_test index6-2.102eqp { + EXPLAIN QUERY PLAN + SELECT b FROM t2 WHERE a=15; +} {~/.*INDEX t2a2.*/} +do_execsql_test index6-2.103 { + SELECT b FROM t2 WHERE a=15 AND a<100; +} {10015} +do_execsql_test index6-2.103eqp { + EXPLAIN QUERY PLAN + SELECT b FROM t2 WHERE a=15 AND a<100; +} {/.*INDEX t2a2.*/} +do_execsql_test index6-2.104 { + SELECT b FROM t2 WHERE a=515 AND a>200; +} {10515} +do_execsql_test index6-2.104eqp { + EXPLAIN QUERY PLAN + SELECT b FROM t2 WHERE a=515 AND a>200; +} {/.*INDEX t2a2.*/} + +# Partial UNIQUE indices +# +do_execsql_test index6-3.1 { + CREATE TABLE t3(a,b); + INSERT INTO t3 SELECT value, value FROM nums WHERE value<200; + UPDATE t3 SET a=999 WHERE b%5!=0; + CREATE UNIQUE INDEX t3a ON t3(a) WHERE a<>999; +} {} +do_test index6-3.2 { + # unable to insert a duplicate row a-value that is not 999. + catchsql { + INSERT INTO t3(a,b) VALUES(150, 'test1'); + } +} {1 {UNIQUE constraint failed: t3.a}} +do_test index6-3.3 { + # can insert multiple rows with a==999 because such rows are not + # part of the unique index. + catchsql { + INSERT INTO t3(a,b) VALUES(999, 'test1'), (999, 'test2'); + } +} {0 {}} +do_execsql_test index6-3.4 { + SELECT count(*) FROM t3 WHERE a=999; +} {162} +integrity_check index6-3.5 + +do_execsql_test index6-4.0 { + VACUUM; + PRAGMA integrity_check; +} {ok} + +# Silently ignore database name qualifiers in partial indices. +# +do_execsql_test index6-5.0 { + CREATE INDEX t3b ON t3(b) WHERE xyzzy.t3.b BETWEEN 5 AND 10; + /* ^^^^^-- ignored */ + ANALYZE; + SELECT count(*) FROM t3 WHERE t3.b BETWEEN 5 AND 10; + SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b'; +} {6 6} + +# Test case for ticket [2ea3e9fe6379fc3f6ce7e090ce483c1a3a80d6c9] from +# 2014-04-13: Partial index causes assertion fault on UPDATE OR REPLACE. +# +do_execsql_test index6-6.0 { + CREATE TABLE t6(a,b); + CREATE UNIQUE INDEX t6ab ON t1(a,b); + CREATE INDEX t6b ON t6(b) WHERE b=1; + INSERT INTO t6(a,b) VALUES(123,456); + SELECT * FROM t6; +} {123 456} +do_execsql_test index6-6.1 { + UPDATE OR REPLACE t6 SET b=789; + SELECT * FROM t6; +} {123 789} +do_execsql_test index6-6.2 { + PRAGMA integrity_check; +} {ok} + + +finish_test diff --git a/test/index7.test b/test/index7.test new file mode 100644 index 0000000..1c81f60 --- /dev/null +++ b/test/index7.test @@ -0,0 +1,251 @@ +# 2013-11-04 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Test cases for partial indices in WITHOUT ROWID tables +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !vtab { + finish_test + return +} + +load_static_extension db wholenumber; +do_test index7-1.1 { + # Able to parse and manage partial indices + execsql { + CREATE TABLE t1(a,b,c PRIMARY KEY) WITHOUT rowid; + CREATE INDEX t1a ON t1(a) WHERE a IS NOT NULL; + CREATE INDEX t1b ON t1(b) WHERE b>10; + CREATE VIRTUAL TABLE nums USING wholenumber; + INSERT INTO t1(a,b,c) + SELECT CASE WHEN value%3!=0 THEN value END, value, value + FROM nums WHERE value<=20; + SELECT count(a), count(b) FROM t1; + PRAGMA integrity_check; + } +} {14 20 ok} + +# Make sure the count(*) optimization works correctly with +# partial indices. Ticket [a5c8ed66cae16243be6] 2013-10-03. +# +do_execsql_test index7-1.1.1 { + SELECT count(*) FROM t1; +} {20} + +# Error conditions during parsing... +# +do_test index7-1.2 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE x IS NOT NULL; + } +} {1 {no such column: x}} +do_test index7-1.3 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE EXISTS(SELECT * FROM t1); + } +} {1 {subqueries prohibited in partial index WHERE clauses}} +do_test index7-1.4 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE a!=?1; + } +} {1 {parameters prohibited in partial index WHERE clauses}} +do_test index7-1.5 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE a!=random(); + } +} {1 {functions prohibited in partial index WHERE clauses}} +do_test index7-1.6 { + catchsql { + CREATE INDEX bad1 ON t1(a,b) WHERE a NOT LIKE 'abc%'; + } +} {1 {functions prohibited in partial index WHERE clauses}} + +do_test index7-1.10 { + execsql { + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {t1 {20 1} t1a {14 1} t1b {10 1} ok} + +# STAT1 shows the partial indices have a reduced number of +# rows. +# +do_test index7-1.11 { + execsql { + UPDATE t1 SET a=b; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {t1 {20 1} t1a {20 1} t1b {10 1} ok} + +do_test index7-1.11b { + execsql { + UPDATE t1 SET a=NULL WHERE b%3!=0; + UPDATE t1 SET b=b+100; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {t1 {20 1} t1a {6 1} t1b {20 1} ok} + +do_test index7-1.12 { + execsql { + UPDATE t1 SET a=CASE WHEN b%3!=0 THEN b END; + UPDATE t1 SET b=b-100; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {t1 {20 1} t1a {13 1} t1b {10 1} ok} + +do_test index7-1.13 { + execsql { + DELETE FROM t1 WHERE b BETWEEN 8 AND 12; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {t1 {15 1} t1a {10 1} t1b {8 1} ok} + +do_test index7-1.14 { + execsql { + REINDEX; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {t1 {15 1} t1a {10 1} t1b {8 1} ok} + +do_test index7-1.15 { + execsql { + CREATE INDEX t1c ON t1(c); + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + PRAGMA integrity_check; + } +} {t1 {15 1} t1a {10 1} t1b {8 1} t1c {15 1} ok} + +# Queries use partial indices as appropriate times. +# +do_test index7-2.1 { + execsql { + CREATE TABLE t2(a,b PRIMARY KEY) without rowid; + INSERT INTO t2(a,b) SELECT value, value FROM nums WHERE value<1000; + UPDATE t2 SET a=NULL WHERE b%5==0; + CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL; + SELECT count(*) FROM t2 WHERE a IS NOT NULL; + } +} {800} +do_test index7-2.2 { + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t2 WHERE a=5; + } +} {/.* TABLE t2 USING COVERING INDEX t2a1 .*/} +ifcapable stat4||stat3 { + do_test index7-2.3stat4 { + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t2 WHERE a IS NOT NULL; + } + } {/.* TABLE t2 USING COVERING INDEX t2a1 .*/} +} else { + do_test index7-2.3stat4 { + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t2 WHERE a IS NOT NULL AND a>0; + } + } {/.* TABLE t2 USING COVERING INDEX t2a1 .*/} +} +do_test index7-2.4 { + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t2 WHERE a IS NULL; + } +} {~/.*INDEX t2a1.*/} + +do_execsql_test index7-2.101 { + DROP INDEX t2a1; + UPDATE t2 SET a=b, b=b+10000; + SELECT b FROM t2 WHERE a=15; +} {10015} +do_execsql_test index7-2.102 { + CREATE INDEX t2a2 ON t2(a) WHERE a<100 OR a>200; + SELECT b FROM t2 WHERE a=15; + PRAGMA integrity_check; +} {10015 ok} +do_execsql_test index7-2.102eqp { + EXPLAIN QUERY PLAN + SELECT b FROM t2 WHERE a=15; +} {~/.*INDEX t2a2.*/} +do_execsql_test index7-2.103 { + SELECT b FROM t2 WHERE a=15 AND a<100; +} {10015} +do_execsql_test index7-2.103eqp { + EXPLAIN QUERY PLAN + SELECT b FROM t2 WHERE a=15 AND a<100; +} {/.*INDEX t2a2.*/} +do_execsql_test index7-2.104 { + SELECT b FROM t2 WHERE a=515 AND a>200; +} {10515} +do_execsql_test index7-2.104eqp { + EXPLAIN QUERY PLAN + SELECT b FROM t2 WHERE a=515 AND a>200; +} {/.*INDEX t2a2.*/} + +# Partial UNIQUE indices +# +do_execsql_test index7-3.1 { + CREATE TABLE t3(a,b PRIMARY KEY) without rowid; + INSERT INTO t3 SELECT value, value FROM nums WHERE value<200; + UPDATE t3 SET a=999 WHERE b%5!=0; + CREATE UNIQUE INDEX t3a ON t3(a) WHERE a<>999; +} {} +do_test index7-3.2 { + # unable to insert a duplicate row a-value that is not 999. + catchsql { + INSERT INTO t3(a,b) VALUES(150, 'test1'); + } +} {1 {UNIQUE constraint failed: t3.a}} +do_test index7-3.3 { + # can insert multiple rows with a==999 because such rows are not + # part of the unique index. + catchsql { + INSERT INTO t3(a,b) VALUES(999, 'test1'), (999, 'test2'); + } +} {0 {}} +do_execsql_test index7-3.4 { + SELECT count(*) FROM t3 WHERE a=999; +} {162} +integrity_check index7-3.5 + +do_execsql_test index7-4.0 { + VACUUM; + PRAGMA integrity_check; +} {ok} + +# Silently ignore database name qualifiers in partial indices. +# +do_execsql_test index7-5.0 { + CREATE INDEX t3b ON t3(b) WHERE xyzzy.t3.b BETWEEN 5 AND 10; + /* ^^^^^-- ignored */ + ANALYZE; + SELECT count(*) FROM t3 WHERE t3.b BETWEEN 5 AND 10; + SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b'; +} {6 6} + +finish_test diff --git a/test/indexedby.test b/test/indexedby.test index 7ccc4de..f95c167 100644 --- a/test/indexedby.test +++ b/test/indexedby.test @@ -13,6 +13,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set ::testprefix indexedby # Create a schema with some indexes. # @@ -42,15 +43,15 @@ proc EQP {sql} { # do_execsql_test indexedby-1.2 { EXPLAIN QUERY PLAN select * from t1 WHERE a = 10; -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-1.3 { EXPLAIN QUERY PLAN select * from t1 ; -} {0 0 0 {SCAN TABLE t1 (~1000000 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-1.4 { EXPLAIN QUERY PLAN select * from t1, t2 WHERE c = 10; } { - 0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?) (~10 rows)} - 0 1 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)} + 0 1 0 {SCAN TABLE t1} } # Parser tests. Test that an INDEXED BY or NOT INDEX clause can be @@ -85,21 +86,21 @@ do_test indexedby-2.7 { # do_execsql_test indexedby-3.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two' -} {0 0 0 {SCAN TABLE t1 (~10000 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-3.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two' -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-3.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two' -} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_test indexedby-3.4 { catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' } -} {1 {cannot use index: i2}} +} {1 {no query solution}} do_test indexedby-3.5 { catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a } -} {1 {cannot use index: i2}} +} {1 {no query solution}} do_test indexedby-3.6 { catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' } } {0 {}} @@ -110,14 +111,14 @@ do_test indexedby-3.7 { do_execsql_test indexedby-3.8 { EXPLAIN QUERY PLAN SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e -} {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1 (~1000000 rows)}} +} {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1}} do_execsql_test indexedby-3.9 { EXPLAIN QUERY PLAN SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 -} {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}} do_test indexedby-3.10 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 } -} {1 {cannot use index: sqlite_autoindex_t3_1}} +} {1 {no query solution}} do_test indexedby-3.11 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 } } {1 {no such index: sqlite_autoindex_t3_2}} @@ -127,25 +128,25 @@ do_test indexedby-3.11 { do_execsql_test indexedby-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE a = c } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} - 0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?) (~10 rows)} + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)} } do_execsql_test indexedby-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c } { - 0 0 1 {SCAN TABLE t2 (~1000000 rows)} - 0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)} + 0 0 1 {SCAN TABLE t2} + 0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} } do_test indexedby-4.3 { catchsql { SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c } -} {1 {cannot use index: i1}} +} {1 {no query solution}} do_test indexedby-4.4 { catchsql { SELECT * FROM t2 INDEXED BY i3, t1 INDEXED BY i1 WHERE a=c } -} {1 {cannot use index: i3}} +} {1 {no query solution}} # Test embedding an INDEXED BY in a CREATE VIEW statement. This block # also tests that nothing bad happens if an index refered to by @@ -154,10 +155,10 @@ do_test indexedby-4.4 { do_execsql_test indexedby-5.1 { CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5; EXPLAIN QUERY PLAN SELECT * FROM v2 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~250000 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} do_execsql_test indexedby-5.2 { EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~25000 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} do_test indexedby-5.3 { execsql { DROP INDEX i1 } catchsql { SELECT * FROM v2 } @@ -166,7 +167,7 @@ do_test indexedby-5.4 { # Recreate index i1 in such a way as it cannot be used by the view query. execsql { CREATE INDEX i1 ON t1(b) } catchsql { SELECT * FROM v2 } -} {1 {cannot use index: i1}} +} {1 {no query solution}} do_test indexedby-5.5 { # Drop and recreate index i1 again. This time, create it so that it can # be used by the query. @@ -178,54 +179,54 @@ do_test indexedby-5.5 { # do_execsql_test indexedby-6.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 10 ORDER BY rowid -} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_execsql_test indexedby-6.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid -} {0 0 0 {SCAN TABLE t1 USING INTEGER PRIMARY KEY (~100000 rows)}} +} {0 0 0 {SCAN TABLE t1}} # Test that "INDEXED BY" can be used in a DELETE statement. # do_execsql_test indexedby-7.1 { EXPLAIN QUERY PLAN DELETE FROM t1 WHERE a = 5 -} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-7.2 { EXPLAIN QUERY PLAN DELETE FROM t1 NOT INDEXED WHERE a = 5 -} {0 0 0 {SCAN TABLE t1 (~100000 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-7.3 { EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 -} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-7.4 { EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-7.5 { EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_test indexedby-7.6 { catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5} -} {1 {cannot use index: i2}} +} {1 {no query solution}} # Test that "INDEXED BY" can be used in an UPDATE statement. # do_execsql_test indexedby-8.1 { EXPLAIN QUERY PLAN UPDATE t1 SET rowid=rowid+1 WHERE a = 5 -} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-8.2 { EXPLAIN QUERY PLAN UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 -} {0 0 0 {SCAN TABLE t1 (~100000 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-8.3 { EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 -} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-8.4 { EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-8.5 { EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_test indexedby-8.6 { catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5} -} {1 {cannot use index: i2}} +} {1 {no query solution}} # Test that bug #3560 is fixed. # @@ -243,10 +244,10 @@ do_test indexedby-9.2 { joinme as j indexed by joinme_id_text_idx on ( m.id = j.id_int) } -} {1 {cannot use index: joinme_id_text_idx}} +} {1 {no query solution}} do_test indexedby-9.3 { catchsql { select * from maintable, joinme INDEXED by joinme_id_text_idx } -} {1 {cannot use index: joinme_id_text_idx}} +} {1 {no query solution}} # Make sure we can still create tables, indices, and columns whose name # is "indexed". @@ -274,4 +275,50 @@ do_test indexedby-10.3 { } } {1} +#------------------------------------------------------------------------- +# Ensure that the rowid at the end of each index entry may be used +# for equality constraints in the same way as other indexed fields. +# +do_execsql_test 11.1 { + CREATE TABLE x1(a, b TEXT); + CREATE INDEX x1i ON x1(a, b); + INSERT INTO x1 VALUES(1, 1); + INSERT INTO x1 VALUES(1, 1); + INSERT INTO x1 VALUES(1, 1); + INSERT INTO x1 VALUES(1, 1); +} +do_execsql_test 11.2 { + SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid=3; +} {1 1 3} +do_execsql_test 11.3 { + SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3'; +} {1 1 3} +do_execsql_test 11.4 { + SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; +} {1 1 3} +do_eqp_test 11.5 { + SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; +} {0 0 0 {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}} + +do_execsql_test 11.6 { + CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT); + CREATE INDEX x2i ON x2(a, b); + INSERT INTO x2 VALUES(1, 1, 1); + INSERT INTO x2 VALUES(2, 1, 1); + INSERT INTO x2 VALUES(3, 1, 1); + INSERT INTO x2 VALUES(4, 1, 1); +} +do_execsql_test 11.7 { + SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c=3; +} {1 1 3} +do_execsql_test 11.8 { + SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3'; +} {1 1 3} +do_execsql_test 11.9 { + SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; +} {1 1 3} +do_eqp_test 11.10 { + SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; +} {0 0 0 {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}} + finish_test diff --git a/test/insert.test b/test/insert.test index e00b9a8..cb675b9 100644 --- a/test/insert.test +++ b/test/insert.test @@ -398,11 +398,44 @@ ifcapable compound { } {1 2 3 4 5 6 7 8 9} do_test insert-10.2 { catchsql { - INSERT INTO t10 VALUES(11,12,13), (14,15); + INSERT INTO t10 VALUES(11,12,13), (14,15), (16,17,28); } } {1 {all VALUES must have the same number of terms}} } +# Need for the OP_SoftNull opcode +# +do_execsql_test insert-11.1 { + CREATE TABLE t11a AS SELECT '123456789' AS x; + CREATE TABLE t11b (a INTEGER PRIMARY KEY, b, c); + INSERT INTO t11b SELECT x, x, x FROM t11a; + SELECT quote(a), quote(b), quote(c) FROM t11b; +} {123456789 '123456789' '123456789'} + + +# More columns of input than there are columns in the table. +# Ticket http://www.sqlite.org/src/info/e9654505cfda9361 +# +do_execsql_test insert-12.1 { + CREATE TABLE t12a(a,b,c,d,e,f,g); + INSERT INTO t12a VALUES(101,102,103,104,105,106,107); + CREATE TABLE t12b(x); + INSERT INTO t12b(x,rowid,x,x,x,x,x) SELECT * FROM t12a; + SELECT rowid, x FROM t12b; +} {102 101} +do_execsql_test insert-12.2 { + CREATE TABLE tab1( value INTEGER); + INSERT INTO tab1 (value, _rowid_) values( 11, 1); + INSERT INTO tab1 (value, _rowid_) SELECT 22,999; + SELECT * FROM tab1; +} {11 22} +do_execsql_test insert-12.3 { + CREATE TABLE t12c(a, b DEFAULT 'xyzzy', c); + INSERT INTO t12c(a, rowid, c) SELECT 'one', 999, 'two'; + SELECT * FROM t12c; +} {one xyzzy two} + + integrity_check insert-99.0 finish_test diff --git a/test/insert4.test b/test/insert4.test index f4a45c1..889d5e7 100644 --- a/test/insert4.test +++ b/test/insert4.test @@ -54,7 +54,7 @@ do_test insert4-1.1 { catchsql { INSERT INTO t1 SELECT * FROM t2; } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} xferopt_test insert4-1.2 0 do_test insert4-1.3 { execsql { @@ -101,7 +101,7 @@ do_test insert4-2.3.3 { INSERT INTO t1 SELECT * FROM t2 LIMIT 1; SELECT * FROM t1; } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} xferopt_test insert4-2.3.4 0 # Do not run the transfer optimization if there is a DISTINCT @@ -119,7 +119,7 @@ do_test insert4-2.4.3 { DELETE FROM t1; INSERT INTO t1 SELECT DISTINCT * FROM t2; } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t1}} xferopt_test insert4-2.4.4 0 # The following procedure constructs two tables then tries to transfer @@ -253,7 +253,7 @@ ifcapable vacuum { # do_test insert4-5.1 { # Table does not exist. - catchsql { INSERT INTO t2 SELECT * FROM nosuchtable } + catchsql { INSERT INTO t2 SELECT a, b FROM nosuchtable } } {1 {no such table: nosuchtable}} do_test insert4-5.2 { # Number of columns does not match. @@ -315,7 +315,7 @@ do_test insert4-6.6 { catchsql { INSERT INTO t6b SELECT * FROM t6a; } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t6b}} do_test insert4-6.7 { execsql { DROP TABLE t6b; @@ -324,7 +324,7 @@ do_test insert4-6.7 { catchsql { INSERT INTO t6b SELECT * FROM t6a; } -} {1 {constraint failed}} +} {1 {CHECK constraint failed: t6b}} # Ticket [6284df89debdfa61db8073e062908af0c9b6118e] # Disable the xfer optimization if the destination table contains @@ -353,7 +353,7 @@ ifcapable foreignkey { catchsql { INSERT INTO t7b SELECT * FROM t7c; } - } {1 {foreign key constraint failed}} + } {1 {FOREIGN KEY constraint failed}} do_test insert4-7.4 { execsql {SELECT * FROM t7b} } {} @@ -452,7 +452,7 @@ do_test insert4-8.5 { catchsql { INSERT INTO t1 SELECT * FROM t2; } -} {1 {PRIMARY KEY must be unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test insert4-8.6 { execsql { SELECT * FROM t1; @@ -472,7 +472,7 @@ do_test insert4-8.7 { catchsql { INSERT INTO t1 SELECT * FROM t2; } -} {1 {PRIMARY KEY must be unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test insert4-8.8 { execsql { SELECT * FROM t1; @@ -494,7 +494,7 @@ do_test insert4-8.9 { INSERT INTO t1 VALUES(2,3); INSERT INTO t1 SELECT * FROM t2; } -} {1 {PRIMARY KEY must be unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test insert4-8.10 { catchsql {COMMIT} } {1 {cannot commit - no transaction is active}} diff --git a/test/instr.test b/test/instr.test index b328cd1..c8be486 100644 --- a/test/instr.test +++ b/test/instr.test @@ -11,6 +11,11 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the built-in INSTR() functions. # +# EVIDENCE-OF: R-27549-59611 The instr(X,Y) function finds the first +# occurrence of string Y within string X and returns the number of prior +# characters plus 1, or 0 if Y is nowhere found within X. +# + set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -199,12 +204,48 @@ do_test instr-1.54 { do_test instr-1.55 { db eval {SELECT instr(x'78c3a4e282ac79','y');} } {4} -do_test instr-1.56 { + +# EVIDENCE-OF: R-46421-32541 Or, if X and Y are both BLOBs, then +# instr(X,Y) returns one more than the number bytes prior to the first +# occurrence of Y, or 0 if Y does not occur anywhere within X. +# +do_test instr-1.56.1 { db eval {SELECT instr(x'78c3a4e282ac79',x'79');} } {7} -do_test instr-1.57 { +do_test instr-1.56.2 { + db eval {SELECT instr(x'78c3a4e282ac79',x'7a');} +} {0} +do_test instr-1.56.3 { + db eval {SELECT instr(x'78c3a4e282ac79',x'78');} +} {1} +do_test instr-1.56.3 { + db eval {SELECT instr(x'78c3a4e282ac79',x'a4');} +} {3} + +# EVIDENCE-OF: R-17329-35644 If both arguments X and Y to instr(X,Y) are +# non-NULL and are not BLOBs then both are interpreted as strings. +# +do_test instr-1.57.1 { db eval {SELECT instr('xä€y',x'79');} } {4} +do_test instr-1.57.2 { + db eval {SELECT instr('xä€y',x'a4');} +} {0} +do_test instr-1.57.3 { + db eval {SELECT instr(x'78c3a4e282ac79','y');} +} {4} +# EVIDENCE-OF: R-14708-27487 If either X or Y are NULL in instr(X,Y) +# then the result is NULL. +# +do_execsql_test instr-1.60 { + SELECT coalesce(instr(NULL,'abc'), 999); +} {999} +do_execsql_test instr-1.61 { + SELECT coalesce(instr('abc',NULL), 999); +} {999} +do_execsql_test instr-1.62 { + SELECT coalesce(instr(NULL,NULL), 999); +} {999} finish_test diff --git a/test/intpkey.test b/test/intpkey.test index db39421..41858e5 100644 --- a/test/intpkey.test +++ b/test/intpkey.test @@ -76,7 +76,7 @@ do_test intpkey-1.6 { INSERT INTO t1 VALUES(5,'second','entry'); }} msg] lappend r $msg -} {1 {PRIMARY KEY must be unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test intpkey-1.7 { execsql { SELECT rowid, * FROM t1; @@ -125,8 +125,11 @@ do_test intpkey-1.12.1 { } } {4 one two} do_test intpkey-1.12.2 { - set sqlite_query_plan -} {t1 *} + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a==4; + } +} {/SEARCH TABLE t1 /} # Try to insert a non-integer value into the primary key field. This # should result in a data type mismatch. diff --git a/test/io.test b/test/io.test index 11f9cc8..c5086c1 100644 --- a/test/io.test +++ b/test/io.test @@ -641,4 +641,3 @@ foreach {tn sql} { sqlite3_simulate_device -char {} -sectorsize 0 finish_test - diff --git a/test/ioerr.test b/test/ioerr.test index b237439..e59647f 100644 --- a/test/ioerr.test +++ b/test/ioerr.test @@ -258,7 +258,7 @@ do_ioerr_test ioerr-10 -ckrefcount true -tclprep { INSERT INTO t1 SELECT (a+500)%900, 'good string' FROM t1; }} msg - if {$msg != "column a is not unique"} { + if {$msg != "UNIQUE constraint failed: t1.a"} { error $msg } } diff --git a/test/ioerr6.test b/test/ioerr6.test index 66c48ad..d1847b2 100644 --- a/test/ioerr6.test +++ b/test/ioerr6.test @@ -89,4 +89,3 @@ do_faultsim_test 3 -faults full* -prep { } finish_test - diff --git a/test/join.test b/test/join.test index 88ac04f..4c83fa6 100644 --- a/test/join.test +++ b/test/join.test @@ -36,6 +36,17 @@ do_test join-1.2 { } } {1 2 3 2 3 4 3 4 5} +# A FROM clause of the form: "<table>, <table> ON <expr>" is not +# allowed by the SQLite syntax diagram, nor by any other SQL database +# engine that we are aware of. Nevertheless, historic versions of +# SQLite have allowed it. We need to continue to support it moving +# forward to prevent breakage of legacy applications. Though, we will +# not advertise it as being supported. +# +do_execsql_test join-1.2.1 { + SELECT t1.rowid, t2.rowid, '|' FROM t1, t2 ON t1.a=t2.b; +} {1 1 | 2 2 | 3 3 |} + do_test join-1.3 { execsql2 { SELECT * FROM t1 NATURAL JOIN t2; @@ -641,4 +652,39 @@ do_test join-11.10 { execsql { SELECT * FROM t2 NATURAL JOIN t1 } } {1 one 2 two} +#------------------------------------------------------------------------- +# Test that at most 64 tables are allowed in a join. +# +do_execsql_test join-12.1 { + CREATE TABLE t14(x); + INSERT INTO t14 VALUES('abcdefghij'); +} + +proc jointest {tn nTbl res} { + set sql "SELECT 1 FROM [string repeat t14, [expr $nTbl-1]] t14;" + uplevel [list do_catchsql_test $tn $sql $res] +} + +jointest join-12.2 30 {0 1} +jointest join-12.3 63 {0 1} +jointest join-12.4 64 {0 1} +jointest join-12.5 65 {1 {at most 64 tables in a join}} +jointest join-12.6 66 {1 {at most 64 tables in a join}} +jointest join-12.7 127 {1 {at most 64 tables in a join}} +jointest join-12.8 128 {1 {at most 64 tables in a join}} +jointest join-12.9 1000 {1 {at most 64 tables in a join}} + +# If SQLite is built with SQLITE_MEMDEBUG, then the huge number of realloc() +# calls made by the following test cases are too time consuming to run. +# Without SQLITE_MEMDEBUG, realloc() is fast enough that these are not +# a problem. +ifcapable pragma&&compileoption_diags { + if {[lsearch [db eval {PRAGMA compile_options}] MEMDEBUG]<0} { + jointest join-12.10 65534 {1 {at most 64 tables in a join}} + jointest join-12.11 65535 {1 {too many references to "t14": max 65535}} + jointest join-12.12 65536 {1 {too many references to "t14": max 65535}} + jointest join-12.13 65537 {1 {too many references to "t14": max 65535}} + } +} + finish_test diff --git a/test/keyword1.test b/test/keyword1.test index 9483120..2bc1ff5 100644 --- a/test/keyword1.test +++ b/test/keyword1.test @@ -65,6 +65,7 @@ set kwlist { pragma query raise + recursive regexp reindex release @@ -80,6 +81,8 @@ set kwlist { vacuum view virtual + with + without }; set exprkw { cast diff --git a/test/lastinsert.test b/test/lastinsert.test index adeb798..c5bc267 100644 --- a/test/lastinsert.test +++ b/test/lastinsert.test @@ -36,6 +36,17 @@ do_test lastinsert-1.1 { } } {0 3} +# EVIDENCE-OF: R-47220-63683 The sqlite3_last_insert_rowid() function +# does not work for WITHOUT ROWID tables. +# +do_test lastinsert-1.1w { + catchsql { + create table t1w (k integer primary key) WITHOUT ROWID; + insert into t1w values (123456); + select last_insert_rowid(); -- returns 3 from above. + } +} {0 3} + # LIRID unchanged after an update on a table do_test lastinsert-1.2 { catchsql { diff --git a/test/like.test b/test/like.test index 80ba418..923272c 100644 --- a/test/like.test +++ b/test/like.test @@ -156,14 +156,27 @@ ifcapable !like_opt { # This procedure executes the SQL. Then it appends to the result the # "sort" or "nosort" keyword (as in the cksort procedure above) then -# it appends the ::sqlite_query_plan variable. +# it appends the names of the table and index used. # proc queryplan {sql} { set ::sqlite_sort_count 0 set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x - return [concat $data $::sqlite_query_plan] + set eqp [execsql "EXPLAIN QUERY PLAN $sql"] + # puts eqp=$eqp + foreach {a b c x} $eqp { + if {[regexp { TABLE (\w+ AS )?(\w+) USING COVERING INDEX (\w+)\y} \ + $x all as tab idx]} { + lappend data {} $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ + $x all as tab idx]} { + lappend data $tab $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { + lappend data $tab * + } + } + return $data } # Perform tests on the like optimization. @@ -176,7 +189,7 @@ do_test like-3.1 { queryplan { SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1; } -} {ABC {ABC abc xyz} abc abcd sort t1 {}} +} {ABC {ABC abc xyz} abc abcd sort t1 *} do_test like-3.2 { set sqlite_like_count } {12} @@ -269,8 +282,8 @@ do_test like-3.12 { # do_test like-3.13 { set sqlite_like_count 0 + db eval {PRAGMA case_sensitive_like=off;} queryplan { - PRAGMA case_sensitive_like=off; SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1; } } {ABC {ABC abc xyz} abc abcd nosort {} i1} @@ -282,12 +295,14 @@ do_test like-3.14 { # do_test like-3.15 { set sqlite_like_count 0 - queryplan { + db eval { PRAGMA case_sensitive_like=on; DROP INDEX i1; + } + queryplan { SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1; } -} {abc abcd sort t1 {}} +} {abc abcd sort t1 *} do_test like-3.16 { set sqlite_like_count } 12 @@ -299,7 +314,7 @@ do_test like-3.17 { queryplan { SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1; } -} {abc abcd sort t1 {}} +} {abc abcd sort t1 *} do_test like-3.18 { set sqlite_like_count } 12 @@ -318,8 +333,8 @@ do_test like-3.20 { } 0 do_test like-3.21 { set sqlite_like_count 0 + db eval {PRAGMA case_sensitive_like=on;} queryplan { - PRAGMA case_sensitive_like=on; SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1; } } {abc abcd nosort {} i1} @@ -328,8 +343,8 @@ do_test like-3.22 { } 0 do_test like-3.23 { set sqlite_like_count 0 + db eval {PRAGMA case_sensitive_like=off;} queryplan { - PRAGMA case_sensitive_like=off; SELECT x FROM t1 WHERE x GLOB 'a[bc]d' ORDER BY 1; } } {abd acd nosort {} i1} @@ -809,60 +824,66 @@ do_test like-11.0 { } } {12} do_test like-11.1 { + db eval {PRAGMA case_sensitive_like=OFF;} queryplan { - PRAGMA case_sensitive_like=OFF; SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; } } {abc abcd ABC ABCD nosort t11 *} do_test like-11.2 { + db eval {PRAGMA case_sensitive_like=ON;} queryplan { - PRAGMA case_sensitive_like=ON; SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; } } {abc abcd nosort t11 *} do_test like-11.3 { - queryplan { + db eval { PRAGMA case_sensitive_like=OFF; CREATE INDEX t11b ON t11(b); + } + queryplan { SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY +a; } } {abc abcd ABC ABCD sort {} t11b} do_test like-11.4 { + db eval {PRAGMA case_sensitive_like=ON;} queryplan { - PRAGMA case_sensitive_like=ON; SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; } } {abc abcd nosort t11 *} do_test like-11.5 { - queryplan { + db eval { PRAGMA case_sensitive_like=OFF; DROP INDEX t11b; CREATE INDEX t11bnc ON t11(b COLLATE nocase); + } + queryplan { SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY +a; } } {abc abcd ABC ABCD sort {} t11bnc} do_test like-11.6 { + db eval {CREATE INDEX t11bb ON t11(b COLLATE binary);} queryplan { - CREATE INDEX t11bb ON t11(b COLLATE binary); SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY +a; } } {abc abcd ABC ABCD sort {} t11bnc} do_test like-11.7 { + db eval {PRAGMA case_sensitive_like=ON;} queryplan { - PRAGMA case_sensitive_like=ON; SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY +a; } } {abc abcd sort {} t11bb} do_test like-11.8 { + db eval {PRAGMA case_sensitive_like=OFF;} queryplan { - PRAGMA case_sensitive_like=OFF; SELECT b FROM t11 WHERE b GLOB 'abc*' ORDER BY +a; } } {abc abcd sort {} t11bb} do_test like-11.9 { - queryplan { + db eval { CREATE INDEX t11cnc ON t11(c COLLATE nocase); CREATE INDEX t11cb ON t11(c COLLATE binary); + } + queryplan { SELECT c FROM t11 WHERE c LIKE 'abc%' ORDER BY +a; } } {abc abcd ABC ABCD sort {} t11cnc} @@ -872,5 +893,60 @@ do_test like-11.10 { } } {abc abcd sort {} t11cb} +# A COLLATE clause on the pattern does not change the result of a +# LIKE operator. +# +do_execsql_test like-12.1 { + CREATE TABLE t12nc(id INTEGER, x TEXT UNIQUE COLLATE nocase); + INSERT INTO t12nc VALUES(1,'abcde'),(2,'uvwxy'),(3,'ABCDEF'); + CREATE TABLE t12b(id INTEGER, x TEXT UNIQUE COLLATE binary); + INSERT INTO t12b VALUES(1,'abcde'),(2,'uvwxy'),(3,'ABCDEF'); + SELECT id FROM t12nc WHERE x LIKE 'abc%' ORDER BY +id; +} {1 3} +do_execsql_test like-12.2 { + SELECT id FROM t12b WHERE x LIKE 'abc%' ORDER BY +id; +} {1 3} +do_execsql_test like-12.3 { + SELECT id FROM t12nc WHERE x LIKE 'abc%' COLLATE binary ORDER BY +id; +} {1 3} +do_execsql_test like-12.4 { + SELECT id FROM t12b WHERE x LIKE 'abc%' COLLATE binary ORDER BY +id; +} {1 3} +do_execsql_test like-12.5 { + SELECT id FROM t12nc WHERE x LIKE 'abc%' COLLATE nocase ORDER BY +id; +} {1 3} +do_execsql_test like-12.6 { + SELECT id FROM t12b WHERE x LIKE 'abc%' COLLATE nocase ORDER BY +id; +} {1 3} + +# Adding a COLLATE clause to the pattern of a LIKE operator does nothing +# to change the suitability of using an index to satisfy that LIKE +# operator. +# +do_execsql_test like-12.11 { + EXPLAIN QUERY PLAN + SELECT id FROM t12nc WHERE x LIKE 'abc%' ORDER BY +id; +} {/SEARCH/} +do_execsql_test like-12.12 { + EXPLAIN QUERY PLAN + SELECT id FROM t12b WHERE x LIKE 'abc%' ORDER BY +id; +} {/SCAN/} +do_execsql_test like-12.13 { + EXPLAIN QUERY PLAN + SELECT id FROM t12nc WHERE x LIKE 'abc%' COLLATE nocase ORDER BY +id; +} {/SEARCH/} +do_execsql_test like-12.14 { + EXPLAIN QUERY PLAN + SELECT id FROM t12b WHERE x LIKE 'abc%' COLLATE nocase ORDER BY +id; +} {/SCAN/} +do_execsql_test like-12.15 { + EXPLAIN QUERY PLAN + SELECT id FROM t12nc WHERE x LIKE 'abc%' COLLATE binary ORDER BY +id; +} {/SEARCH/} +do_execsql_test like-12.16 { + EXPLAIN QUERY PLAN + SELECT id FROM t12b WHERE x LIKE 'abc%' COLLATE binary ORDER BY +id; +} {/SCAN/} + finish_test diff --git a/test/limit.test b/test/limit.test index c5b75c2..5d6ef33 100644 --- a/test/limit.test +++ b/test/limit.test @@ -616,4 +616,24 @@ do_test limit-13.81 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 8} } {} +do_execsql_test limit-14.1 { + SELECT 123 LIMIT 1 OFFSET 0 +} {123} +do_execsql_test limit-14.2 { + SELECT 123 LIMIT 1 OFFSET 1 +} {} +do_execsql_test limit-14.3 { + SELECT 123 LIMIT 0 OFFSET 0 +} {} +do_execsql_test limit-14.4 { + SELECT 123 LIMIT 0 OFFSET 1 +} {} +do_execsql_test limit-14.6 { + SELECT 123 LIMIT -1 OFFSET 0 +} {123} +do_execsql_test limit-14.7 { + SELECT 123 LIMIT -1 OFFSET 1 +} {} + + finish_test diff --git a/test/loadext.test b/test/loadext.test index 0d5b841..7ba4c0c 100644 --- a/test/loadext.test +++ b/test/loadext.test @@ -66,6 +66,12 @@ if {$::tcl_platform(os) eq "Darwin"} { set dlerror_nosymbol {dlsym(XXX, %2$s): symbol not found} } +if {$::tcl_platform(platform) eq "windows"} { + set dlerror_nosuchfile {The specified module could not be found.*} + set dlerror_notadll {%%1 is not a valid Win32 application.*} + set dlerror_nosymbol {The specified procedure could not be found.*} +} + # Make sure the test extension actually exists. If it does not # exist, try to create it. If unable to create it, then skip this # test file. @@ -167,7 +173,7 @@ do_test loadext-2.3 { regsub {0x[1234567890abcdefABCDEF]*} $msg XXX msg } list $rc $msg -} [list 1 [format $dlerror_nosymbol $testextension icecream]] +} /[list 1 [format $dlerror_nosymbol $testextension icecream]]/ # Try to load an extension for which the entry point fails (returns non-zero) # @@ -267,10 +273,17 @@ do_malloc_test loadext-5 -tclprep { } -tclbody { if {[autoinstall_test_functions]==7} {error "out of memory"} } -do_malloc_test loadext-6 -tclbody { - db enable_load_extension 1 - sqlite3_load_extension db $::testextension testloadext_init + +# On Windows, this malloc test must be skipped because the winDlOpen +# function itself can fail due to "out of memory" conditions. +# +if {$::tcl_platform(platform) ne "windows"} { + do_malloc_test loadext-6 -tclbody { + db enable_load_extension 1 + sqlite3_load_extension db $::testextension testloadext_init + } } + autoinstall_test_functions finish_test diff --git a/test/loadext2.test b/test/loadext2.test index 3d01539..d5b6ea8 100644 --- a/test/loadext2.test +++ b/test/loadext2.test @@ -43,6 +43,19 @@ do_test loadext2-1.2 { } } {1 {no such function: cube}} +# Extensions loaders not currently registered +# +do_test loadext2-1.2.1 { + sqlite3_cancel_auto_extension_sqr +} {0} +do_test loadext2-1.2.2 { + sqlite3_cancel_auto_extension_sqr +} {0} +do_test loadext2-1.2.3 { + sqlite3_cancel_auto_extension_sqr +} {0} + + # Register auto-loaders. Still functions do not exist. # do_test loadext2-1.3 { @@ -76,8 +89,19 @@ do_test loadext2-1.6 { # Reset extension auto loading. Existing extensions still exist. # -do_test loadext2-1.7 { - sqlite3_reset_auto_extension +do_test loadext2-1.7.1 { + sqlite3_cancel_auto_extension_sqr +} {1} +do_test loadext2-1.7.2 { + sqlite3_cancel_auto_extension_sqr +} {0} +do_test loadext2-1.7.3 { + sqlite3_cancel_auto_extension_cube +} {1} +do_test loadext2-1.7.4 { + sqlite3_cancel_auto_extension_cube +} {0} +do_test loadext2-1.7.5 { catchsql { SELECT sqr(2) } diff --git a/test/lock7.test b/test/lock7.test index 49bc147..02f2c6c 100644 --- a/test/lock7.test +++ b/test/lock7.test @@ -58,4 +58,3 @@ db1 close db2 close finish_test - diff --git a/test/malloc.test b/test/malloc.test index 5d03aa8..4276b58 100644 --- a/test/malloc.test +++ b/test/malloc.test @@ -20,6 +20,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set ::testprefix malloc # Only run these tests if memory debugging is turned on. diff --git a/test/malloc5.test b/test/malloc5.test index c02f65e..6abedf7 100644 --- a/test/malloc5.test +++ b/test/malloc5.test @@ -205,6 +205,7 @@ do_test malloc5-4.1 { execsql "INSERT INTO abc VALUES($i, $i, '[string repeat X 100]');" } execsql {COMMIT;} + db cache flush sqlite3_release_memory sqlite3_memory_highwater 1 execsql {SELECT * FROM abc} @@ -213,6 +214,7 @@ do_test malloc5-4.1 { expr $nMaxBytes > 1000000 } {1} do_test malloc5-4.2 { + db cache flush sqlite3_release_memory sqlite3_soft_heap_limit 100000 sqlite3_memory_highwater 1 diff --git a/test/mallocA.test b/test/mallocA.test index 8995127..61e88a6 100644 --- a/test/mallocA.test +++ b/test/mallocA.test @@ -15,6 +15,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl +set testprefix mallocA # Only run these tests if memory debugging is turned on. # @@ -40,7 +41,6 @@ db eval { db close copy_file test.db test.db.bu - do_malloc_test mallocA-1 -testdb test.db.bu -sqlbody { ANALYZE } @@ -53,6 +53,7 @@ do_malloc_test mallocA-1.2 -testdb test.db.bu -sqlbody { do_malloc_test mallocA-1.3 -testdb test.db.bu -sqlbody { ANALYZE main.t1 } + ifcapable reindex { do_malloc_test mallocA-2 -testdb test.db.bu -sqlbody { REINDEX; @@ -68,6 +69,53 @@ ifcapable reindex { } } +reset_db +sqlite3_db_config_lookaside db 0 0 0 +do_execsql_test 6-prep { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); + INSERT INTO t1 VALUES('abc', 'w'); -- rowid=1 + INSERT INTO t1 VALUES('abc', 'x'); -- rowid=2 + INSERT INTO t1 VALUES('abc', 'y'); -- rowid=3 + INSERT INTO t1 VALUES('abc', 'z'); -- rowid=4 + + INSERT INTO t1 VALUES('def', 'w'); -- rowid=5 + INSERT INTO t1 VALUES('def', 'x'); -- rowid=6 + INSERT INTO t1 VALUES('def', 'y'); -- rowid=7 + INSERT INTO t1 VALUES('def', 'z'); -- rowid=8 + + ANALYZE; +} + +do_faultsim_test 6.1 -faults oom* -body { + execsql { SELECT rowid FROM t1 WHERE a='abc' AND b='x' } +} -test { + faultsim_test_result [list 0 2] +} +do_faultsim_test 6.2 -faults oom* -body { + execsql { SELECT rowid FROM t1 WHERE a='abc' AND b<'y' } +} -test { + faultsim_test_result [list 0 {1 2}] +} +ifcapable stat3 { + do_test 6.3-prep { + execsql { + PRAGMA writable_schema = 1; + CREATE TABLE sqlite_stat4 AS + SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample) AS sample + FROM sqlite_stat3; + } + } {} + do_faultsim_test 6.3 -faults oom* -body { + execsql { + ANALYZE sqlite_master; + SELECT rowid FROM t1 WHERE a='abc' AND b<'y'; + } + } -test { + faultsim_test_result [list 0 {1 2}] + } +} + # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close} diff --git a/test/mallocK.test b/test/mallocK.test index 971bd56..dcf00da 100644 --- a/test/mallocK.test +++ b/test/mallocK.test @@ -16,6 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl +set testprefix mallocK set sql {SELECT * FROM t1, t2 WHERE (a=1 OR a=2)} for {set x 1} {$x<5} {incr x} { @@ -68,5 +69,70 @@ ifcapable vtab { } } +#------------------------------------------------------------------------- +# Test that OOM errors are correctly handled by the code that uses stat4 +# data to estimate the number of rows visited by a skip-scan range query. +# +add_alignment_test_collations db +do_execsql_test 6.0 { + CREATE TABLE t3(a TEXT, b TEXT COLLATE utf16_aligned, c); + INSERT INTO t3 VALUES('one', '.....', 0); + INSERT INTO t3 VALUES('one', '....x', 1); + INSERT INTO t3 VALUES('one', '...x.', 2); + INSERT INTO t3 VALUES('one', '...xx', 3); + INSERT INTO t3 VALUES('one', '..x..', 4); + INSERT INTO t3 VALUES('one', '..x.x', 5); + INSERT INTO t3 VALUES('one', '..xx.', 6); + INSERT INTO t3 VALUES('one', '..xxx', 7); + INSERT INTO t3 VALUES('one', '.x...', 8); + INSERT INTO t3 VALUES('one', '.x..x', 9); + INSERT INTO t3 VALUES('one', '.x.x.', 10); + INSERT INTO t3 VALUES('one', '.x.xx', 11); + INSERT INTO t3 VALUES('one', '.xx..', 12); + INSERT INTO t3 VALUES('one', '.xx.x', 13); + INSERT INTO t3 VALUES('one', '.xxx.', 14); + INSERT INTO t3 VALUES('one', '.xxxx', 15); + + INSERT INTO t3 VALUES('two', 'x....', 16); + INSERT INTO t3 VALUES('two', 'x...x', 17); + INSERT INTO t3 VALUES('two', 'x..x.', 18); + INSERT INTO t3 VALUES('two', 'x..xx', 19); + INSERT INTO t3 VALUES('two', 'x.x..', 20); + INSERT INTO t3 VALUES('two', 'x.x.x', 21); + INSERT INTO t3 VALUES('two', 'x.xx.', 22); + INSERT INTO t3 VALUES('two', 'x.xxx', 23); + INSERT INTO t3 VALUES('two', 'xx...', 24); + INSERT INTO t3 VALUES('two', 'xx..x', 25); + INSERT INTO t3 VALUES('two', 'xx.x.', 26); + INSERT INTO t3 VALUES('two', 'xx.xx', 27); + INSERT INTO t3 VALUES('two', 'xxx..', 28); + INSERT INTO t3 VALUES('two', 'xxx.x', 29); + INSERT INTO t3 VALUES('two', 'xxxx.', 30); + INSERT INTO t3 VALUES('two', 'xxxxx', 31); + + INSERT INTO t3 SELECT * FROM t3; + + CREATE INDEX i3 ON t3(a, b); + ANALYZE; + + SELECT 'x' > '.'; +} {1} + +ifcapable stat4 { + do_eqp_test 6.1 { + SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx'; + } { + 0 0 0 {SEARCH TABLE t3 USING INDEX i3 (ANY(a) AND b>? AND b<?)} + 0 0 0 {USE TEMP B-TREE FOR DISTINCT} + } +} + +do_faultsim_test 6 -faults oom* -body { + db cache flush + db eval { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx' } +} -test { + faultsim_test_result {0 {12 13 14 15}} +} finish_test + diff --git a/test/mallocL.test b/test/mallocL.test new file mode 100644 index 0000000..6532ca5 --- /dev/null +++ b/test/mallocL.test @@ -0,0 +1,43 @@ +# 2014 August 12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This test script is designed to show that the assert() fix at +# [f1cb48f412] really is required. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +set testprefix mallocL + +do_test 1.0 { + for {set i 0} {$i < 40} {incr i} { + lappend cols "c$i" + lappend vals $i + } + + execsql "CREATE TABLE t1([join $cols ,])" + execsql "CREATE INDEX i1 ON t1([join $cols ,])" + execsql "INSERT INTO t1 VALUES([join $vals ,])" +} {} + +for {set j 1} {$j < 40} {incr j} { + set ::sql "SELECT DISTINCT [join [lrange $cols 0 $j] ,] FROM t1" + do_faultsim_test 1.$j -faults oom* -body { + execsql $::sql + } -test { + faultsim_test_result [list 0 [lrange $::vals 0 $::j]] + } +} + + +finish_test + diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl index 2ac619b..b586c88 100644 --- a/test/malloc_common.tcl +++ b/test/malloc_common.tcl @@ -93,6 +93,14 @@ set FAULTSIM(cantopen-persistent) [list \ -injectuninstall cantopen_injectuninstall \ ] +set FAULTSIM(interrupt) [list \ + -injectinstall interrupt_injectinstall \ + -injectstart interrupt_injectstart \ + -injectstop interrupt_injectstop \ + -injecterrlist {{1 interrupted} {1 interrupt}} \ + -injectuninstall interrupt_injectuninstall \ +] + #-------------------------------------------------------------------------- @@ -113,7 +121,9 @@ set FAULTSIM(cantopen-persistent) [list \ proc do_faultsim_test {name args} { global FAULTSIM - set DEFAULT(-faults) [array names FAULTSIM] + foreach n [array names FAULTSIM] { + if {$n != "interrupt"} {lappend DEFAULT(-faults) $n} + } set DEFAULT(-prep) "" set DEFAULT(-body) "" set DEFAULT(-test) "" @@ -255,6 +265,22 @@ proc cantopen_injectstop {} { shmfault cantopen } +# The following procs are used as [do_one_faultsim_test] callbacks +# when injecting SQLITE_INTERRUPT error faults into test cases. +# +proc interrupt_injectinstall {} { +} +proc interrupt_injectuninstall {} { +} +proc interrupt_injectstart {iFail} { + set ::sqlite_interrupt_count $iFail +} +proc interrupt_injectstop {} { + set res [expr $::sqlite_interrupt_count<=0] + set ::sqlite_interrupt_count 0 + set res +} + # This command is not called directly. It is used by the # [faultsim_test_result] command created by [do_faultsim_test] and used # by -test scripts. @@ -383,6 +409,7 @@ proc do_malloc_test {tn args} { if {[string is integer $tn]} { set tn malloc-$tn + catch { set tn $::testprefix-$tn } } if {[info exists ::mallocopts(-start)]} { set start $::mallocopts(-start) diff --git a/test/memdb.test b/test/memdb.test index 802fb1a..a2efc03 100644 --- a/test/memdb.test +++ b/test/memdb.test @@ -240,7 +240,7 @@ foreach {i conf1 conf2 cmd t0 t1 t2} { if {$i>1} break } - if {$t0} {set t1 {column a is not unique}} + if {$t0} {set t1 {UNIQUE constraint failed: t1.a}} do_test memdb-5.$i { if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"} if {$conf2!=""} {set conf2 "ON CONFLICT $conf2"} diff --git a/test/memsubsys1.test b/test/memsubsys1.test index e14a1b3..76b79d0 100644 --- a/test/memsubsys1.test +++ b/test/memsubsys1.test @@ -94,7 +94,7 @@ sqlite3_shutdown sqlite3_config_pagecache [expr 1024+$xtra_size] 20 sqlite3_initialize reset_highwater_marks -build_test_db memsubsys1-2 {PRAGMA page_size=1024} +build_test_db memsubsys1-2 {PRAGMA page_size=1024; PRAGMA mmap_size=0} #show_memstats set MEMORY_MANAGEMENT $sqlite_options(memorymanage) ifcapable !malloc_usable_size { diff --git a/test/misc1.test b/test/misc1.test index 188a283..173b77d 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -235,7 +235,7 @@ do_test misc1-7.4 { catchsql { INSERT INTO t5 VALUES(1,2,4); } -} {1 {columns a, b are not unique}} +} {1 {UNIQUE constraint failed: t5.a, t5.b}} do_test misc1-7.5 { catchsql { INSERT INTO t5 VALUES(0,2,4); @@ -592,4 +592,33 @@ do_test misc1-18.1 { expr {$n>=100} } {1} +# 2014-01-10: In a CREATE TABLE AS, if one or more of the column names +# are an empty string, that is still OK. +# +do_execsql_test misc1-19.1 { + CREATE TABLE t19 AS SELECT 1, 2 AS '', 3; + SELECT * FROM t19; +} {1 2 3} +do_execsql_test misc1-19.2 { + CREATE TABLE t19b AS SELECT 4 AS '', 5 AS '', 6 AS ''; + SELECT * FROM t19b; +} {4 5 6} + +# 2014-05-16: Tests for the SQLITE_TESTCTRL_FAULT_INSTALL feature. +# +unset -nocomplain fault_callbacks +set fault_callbacks {} +proc fault_callback {n} { + lappend ::fault_callbacks $n + return 0 +} +do_test misc1-19.1 { + sqlite3_test_control_fault_install fault_callback + set fault_callbacks +} {0} +do_test misc1-19.2 { + sqlite3_test_control_fault_install + set fault_callbacks +} {0} + finish_test diff --git a/test/misc3.test b/test/misc3.test index 81a8266..bc1f0ff 100644 --- a/test/misc3.test +++ b/test/misc3.test @@ -283,7 +283,7 @@ ifcapable {explain} { }] set y [regexp { 123456789012 } $x] lappend y [regexp { 4.5678 } $x] - lappend y [regexp {,-BINARY} $x] + lappend y [regexp {,-B} $x] } {1 1 1} } else { do_test misc3-6.11-utf8 { @@ -293,7 +293,7 @@ ifcapable {explain} { set y [regexp { 123456789012 } $x] lappend y [regexp { 4.5678 } $x] lappend y [regexp { hello } $x] - lappend y [regexp {,-BINARY} $x] + lappend y [regexp {,-B} $x] } {1 1 1 1} } } diff --git a/test/misc7.test b/test/misc7.test index 72c1cd6..8fd5fe7 100644 --- a/test/misc7.test +++ b/test/misc7.test @@ -15,9 +15,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -do_test misc7-1-misuse { - c_misuse_test -} {} +if {[clang_sanitize_address]==0} { + do_test misc7-1-misuse { + c_misuse_test + } {} +} do_test misc7-2 { c_realloc_test @@ -269,17 +271,17 @@ ifcapable explain { CREATE TABLE abc(a PRIMARY KEY, b, c); EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE rowid = 1; } { - 0 0 0 {SEARCH TABLE abc AS t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SEARCH TABLE abc AS t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test misc7-14.2 { EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE a = 1; } {0 0 0 - {SEARCH TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (a=?) (~1 rows)} + {SEARCH TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (a=?)} } do_execsql_test misc7-14.3 { EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 ORDER BY a; } {0 0 0 - {SCAN TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (~1000000 rows)} + {SCAN TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1} } } @@ -355,7 +357,7 @@ do_ioerr_test misc7-16 -sqlprep { COMMIT; }} msg] - if {!$rc || ($rc && [string first "columns" $msg]==0)} { + if {!$rc || ($rc && [string first "UNIQUE" $msg]==0)} { set msg } else { error $msg diff --git a/test/misuse.test b/test/misuse.test index 71ee011..d5d836c 100644 --- a/test/misuse.test +++ b/test/misuse.test @@ -171,37 +171,40 @@ do_test misuse-4.3 { } msg] lappend v $msg $r } {0 {} SQLITE_BUSY} -do_test misuse-4.4 { + +if {[clang_sanitize_address]==0} { + do_test misuse-4.4 { # Flush the TCL statement cache here, otherwise the sqlite3_close() will # fail because there are still un-finalized() VDBEs. - db cache flush - sqlite3_close $::DB - catchsql2 {SELECT * FROM t1} -} {1 {library routine called out of sequence}} -do_test misuse-4.5 { - catchsql { - SELECT * FROM t1 - } -} {1 {library routine called out of sequence}} + db cache flush + sqlite3_close $::DB + catchsql2 {SELECT * FROM t1} + } {1 {library routine called out of sequence}} + do_test misuse-4.5 { + catchsql { + SELECT * FROM t1 + } + } {1 {library routine called out of sequence}} -# Attempt to use a database after it has been closed. -# -do_test misuse-5.1 { - db close - sqlite3 db test2.db; set ::DB [sqlite3_connection_pointer db] - execsql { - SELECT * FROM t1 - } -} {1 2} -do_test misuse-5.2 { - catchsql2 {SELECT * FROM t1} -} {0 {a b 1 2}} -do_test misuse-5.3 { - db close - set r [catch { - sqlite3_prepare $::DB {SELECT * FROM t1} -1 TAIL - } msg] - lappend r $msg -} {1 {(21) library routine called out of sequence}} + # Attempt to use a database after it has been closed. + # + do_test misuse-5.1 { + db close + sqlite3 db test2.db; set ::DB [sqlite3_connection_pointer db] + execsql { + SELECT * FROM t1 + } + } {1 2} + do_test misuse-5.2 { + catchsql2 {SELECT * FROM t1} + } {0 {a b 1 2}} + do_test misuse-5.3 { + db close + set r [catch { + sqlite3_prepare $::DB {SELECT * FROM t1} -1 TAIL + } msg] + lappend r $msg + } {1 {(21) library routine called out of sequence}} +} finish_test diff --git a/test/mmap3.test b/test/mmap3.test new file mode 100644 index 0000000..07b5152 --- /dev/null +++ b/test/mmap3.test @@ -0,0 +1,98 @@ +# 2013-05-23 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +ifcapable !mmap||!vtab { + finish_test + return +} +source $testdir/lock_common.tcl +set testprefix mmap3 + +do_test mmap3-1.0 { + load_static_extension db wholenumber + db eval { + PRAGMA mmap_size=100000; + CREATE TABLE t1(x, y); + CREATE VIRTUAL TABLE nums USING wholenumber; + INSERT INTO t1 SELECT value, randomblob(value) FROM nums + WHERE value BETWEEN 1 and 1000; + SELECT sum(x), sum(length(y)) from t1; + PRAGMA mmap_size; + } +} {100000 500500 500500 100000} +do_test mmap3-1.2 { + db eval { + PRAGMA mmap_size=50000; + CREATE TABLE t2(a,b); + SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1; + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {50000 nums t1 t2 ok 50000} +do_test mmap3-1.3 { + db eval { + PRAGMA mmap_size=250000; + DROP TABLE t2; + SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1; + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {250000 nums t1 ok 250000} +do_test mmap3-1.4 { + db eval {SELECT x FROM t1 WHERE +x BETWEEN 10 AND 15} { + db eval {PRAGMA mmap_size=150000} + } + db eval { + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {ok 250000} +do_test mmap3-1.5 { + db eval {SELECT x FROM t1 WHERE +x BETWEEN 10 AND 15} { + db eval {PRAGMA mmap_size=0} + } + db eval { + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {ok 250000} +do_test mmap3-1.6 { + db eval {SELECT x FROM t1 WHERE +x BETWEEN 10 AND 15} { + set x [db one {PRAGMA mmap_size}] + } + set x [concat $x [db eval { + PRAGMA quick_check; + PRAGMA mmap_size; + }]] +} {250000 ok 250000} +do_test mmap3-1.7 { + db eval { + PRAGMA mmap_size(0); + CREATE TABLE t3(a,b,c); + SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1; + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {0 nums t1 t3 ok 0} +do_test mmap3-1.8 { + db eval {SELECT x FROM t1 WHERE +x BETWEEN 10 AND 15} { + db eval {PRAGMA mmap_size=75000} + } + db eval { + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {ok 75000} + +finish_test diff --git a/test/mmapfault.test b/test/mmapfault.test new file mode 100644 index 0000000..10c5e25 --- /dev/null +++ b/test/mmapfault.test @@ -0,0 +1,76 @@ +# 2013-05-23 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +ifcapable !mmap { + finish_test + return +} +set testprefix mmapfault + +set a_string_counter 1 +proc a_string {n} { + global a_string_counter + incr a_string_counter + string range [string repeat "${a_string_counter}." $n] 1 $n +} +db func a_string a_string + +do_test 1-pre { + execsql { + CREATE TABLE t1(a UNIQUE, b UNIQUE); + INSERT INTO t1 VALUES(a_string(200), a_string(300)); + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + } + faultsim_save_and_close +} {} + + +do_faultsim_test 1 -prep { + faultsim_restore_and_reopen + db func a_string a_string + execsql { + PRAGMA mmap_size = 1000000; + PRAGMA cache_size = 5; + BEGIN; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + } +} -body { + execsql { INSERT INTO t1 VALUES(a_string(200), a_string(300)) } +} -test { + faultsim_test_result {0 {}} + + if {[sqlite3_get_autocommit db]} { + sqlite3 db2 test.db + set nRow [db2 one {SELECT count(*) FROM t1}] + if {$nRow!=4} { error "Database content appears incorrect (1)" } + db2 close + } + + execsql { INSERT INTO t1 VALUES(a_string(201), a_string(301)) } + set nRow [db one {SELECT count(*) FROM t1}] + if {$nRow!=5 && $nRow!=66 && $nRow!=65} { + error "Database content appears incorrect (2) ($nRow)" + } + + catch { execsql COMMIT } +} + + + +finish_test diff --git a/test/multiplex.test b/test/multiplex.test index 32c87d9..5db56f2 100644 --- a/test/multiplex.test +++ b/test/multiplex.test @@ -68,6 +68,12 @@ proc multiplex_delete {name} { } db close +sqlite3_shutdown +test_sqlite3_log xLog +proc xLog {error_code msg} { + lappend ::log $error_code $msg +} +unset -nocomplain log multiplex_delete test.db multiplex_delete test2.db @@ -188,12 +194,16 @@ do_test multiplex-2.3.1 { } {} +unset -nocomplain ::log do_test multiplex-2.4.1 { sqlite3_multiplex_shutdown } {SQLITE_MISUSE} do_test multiplex-2.4.2 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} +do_test multiplex-2.4.3 { + set ::log +} {SQLITE_MISUSE {sqlite3_multiplex_shutdown() called while database connections are still open}} do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168} do_test multiplex-2.4.5 { db close @@ -583,5 +593,9 @@ do_test multiplex-6.99 { } +catch { db close } catch { sqlite3_multiplex_shutdown } +sqlite3_shutdown +test_sqlite3_log +sqlite3_initialize finish_test diff --git a/test/nolock.test b/test/nolock.test new file mode 100644 index 0000000..331af08 --- /dev/null +++ b/test/nolock.test @@ -0,0 +1,185 @@ +# 2014-05-07 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements regression tests for SQLite library. The +# focus of this file is testing the nolock=1 and immutable=1 query +# parameters and the SQLITE_IOCAP_IMMUTABLE device characteristic. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +unset -nocomplain tvfs_calls +proc tvfs_reset {} { + global tvfs_calls + array set tvfs_calls {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0} +} +proc tvfs_callback {op args} { + global tvfs_calls + incr tvfs_calls($op) + return SQLITE_OK +} +tvfs_reset + +testvfs tvfs +tvfs script tvfs_callback +tvfs filter {xLock xUnlock xCheckReservedLock xAccess} + +############################################################################ +# Verify that the nolock=1 query parameter for URI filenames disables all +# calls to xLock and xUnlock for rollback databases. +# +do_test nolock-1.0 { + db close + forcedelete test.db + tvfs_reset + sqlite db test.db -vfs tvfs + db eval {CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3);} + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) +} {xLock 7 xUnlock 5 xCheckReservedLock 0} + +do_test nolock-1.1 { + db close + forcedelete test.db + tvfs_reset + sqlite db file:test.db?nolock=0 -vfs tvfs -uri 1 + db eval {CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3);} + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) +} {xLock 7 xUnlock 5 xCheckReservedLock 0} + +do_test nolock-1.2 { + db close + forcedelete test.db + tvfs_reset + sqlite db file:test.db?nolock=1 -vfs tvfs -uri 1 + db eval {CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3);} + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) +} {xLock 0 xUnlock 0 xCheckReservedLock 0} + +do_test nolock-1.3 { + db close + tvfs_reset + sqlite db file:test.db?nolock=0 -vfs tvfs -uri 1 -readonly 1 + db eval {SELECT * FROM t1} + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) +} {xLock 2 xUnlock 2 xCheckReservedLock 0} + +do_test nolock-1.4 { + db close + tvfs_reset + sqlite db file:test.db?nolock=1 -vfs tvfs -uri 1 -readonly 1 + db eval {SELECT * FROM t1} + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) +} {xLock 0 xUnlock 0 xCheckReservedLock 0} + +############################################################################# +# Verify that immutable=1 disables both locking and xAccess calls to the +# journal files. +# +do_test nolock-2.0 { + db close + forcedelete test.db + # begin by creating a test database + sqlite3 db test.db + db eval { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES('hello','world'); + CREATE TABLE t2(x,y); + INSERT INTO t2 VALUES(12345,67890); + SELECT * FROM t1, t2; + } +} {hello world 12345 67890} +do_test nolock-2.1 { + tvfs_reset + sqlite3 db2 test.db -vfs tvfs + db2 eval {SELECT * FROM t1, t2} +} {hello world 12345 67890} +do_test nolock-2.2 { + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \ + xAccess $::tvfs_calls(xAccess) +} {xLock 2 xUnlock 2 xCheckReservedLock 0 xAccess 4} + + +do_test nolock-2.11 { + db2 close + tvfs_reset + sqlite3 db2 file:test.db?immutable=0 -vfs tvfs -uri 1 + db2 eval {SELECT * FROM t1, t2} +} {hello world 12345 67890} +do_test nolock-2.12 { + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \ + xAccess $::tvfs_calls(xAccess) +} {xLock 2 xUnlock 2 xCheckReservedLock 0 xAccess 4} + + +do_test nolock-2.21 { + db2 close + tvfs_reset + sqlite3 db2 file:test.db?immutable=1 -vfs tvfs -uri 1 + db2 eval {SELECT * FROM t1, t2} +} {hello world 12345 67890} +do_test nolock-2.22 { + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \ + xAccess $::tvfs_calls(xAccess) +} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0} + +do_test nolock-2.31 { + db2 close + tvfs_reset + sqlite3 db2 file:test.db?immutable=1 -vfs tvfs -uri 1 -readonly 1 + db2 eval {SELECT * FROM t1, t2} +} {hello world 12345 67890} +do_test nolock-2.32 { + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \ + xAccess $::tvfs_calls(xAccess) +} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0} + +############################################################################ +# Verify that the SQLITE_IOCAP_IMMUTABLE flag works +# +do_test nolock-3.1 { + db2 close + tvfs devchar immutable + tvfs_reset + sqlite3 db2 test.db -vfs tvfs + db2 eval {SELECT * FROM t1, t2} +} {hello world 12345 67890} +do_test nolock-3.2 { + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \ + xAccess $::tvfs_calls(xAccess) +} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0} + +do_test nolock-3.11 { + db2 close + tvfs_reset + sqlite3 db2 test.db -vfs tvfs -readonly 1 + db2 eval {SELECT * FROM t1, t2} +} {hello world 12345 67890} +do_test nolock-3.12 { + list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \ + xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \ + xAccess $::tvfs_calls(xAccess) +} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0} + +db2 close +db close +tvfs delete +finish_test diff --git a/test/notify3.test b/test/notify3.test index 446f010..4b5e801 100644 --- a/test/notify3.test +++ b/test/notify3.test @@ -150,4 +150,3 @@ catch { db2 close } sqlite3_enable_shared_cache $esc finish_test - diff --git a/test/notnull.test b/test/notnull.test index 01738a4..23fd33d 100644 --- a/test/notnull.test +++ b/test/notnull.test @@ -47,7 +47,7 @@ do_test notnull-1.2 { INSERT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-1.2b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.3 { catchsql { @@ -62,7 +62,7 @@ do_test notnull-1.4 { INSERT OR REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-1.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.5 { catchsql { @@ -70,7 +70,7 @@ do_test notnull-1.5 { INSERT OR ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-1.5b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.6 { catchsql { @@ -106,7 +106,7 @@ do_test notnull-1.10 { INSERT INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.b may not be NULL}} +} {1 {NOT NULL constraint failed: t1.b}} verify_ex_errcode notnull-1.10b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.11 { catchsql { @@ -149,7 +149,7 @@ do_test notnull-1.16 { INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.c may not be NULL}} +} {1 {NOT NULL constraint failed: t1.c}} verify_ex_errcode notnull-1.16b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.17 { catchsql { @@ -157,7 +157,7 @@ do_test notnull-1.17 { INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } -} {1 {t1.d may not be NULL}} +} {1 {NOT NULL constraint failed: t1.d}} verify_ex_errcode notnull-1.17b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.18 { catchsql { @@ -179,7 +179,7 @@ do_test notnull-1.20 { INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,null); SELECT * FROM t1 order by a; } -} {1 {t1.e may not be NULL}} +} {1 {NOT NULL constraint failed: t1.e}} verify_ex_errcode notnull-1.20b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.21 { catchsql { @@ -196,7 +196,7 @@ do_test notnull-2.1 { UPDATE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-2.1b SQLITE_CONSTRAINT_NOTNULL do_test notnull-2.2 { catchsql { @@ -205,7 +205,7 @@ do_test notnull-2.2 { UPDATE OR REPLACE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-2.2b SQLITE_CONSTRAINT_NOTNULL do_test notnull-2.3 { catchsql { @@ -222,7 +222,7 @@ do_test notnull-2.4 { UPDATE OR ABORT t1 SET a=null; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-2.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-2.5 { catchsql { @@ -231,7 +231,7 @@ do_test notnull-2.5 { UPDATE t1 SET b=null; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.b may not be NULL}} +} {1 {NOT NULL constraint failed: t1.b}} verify_ex_errcode notnull-2.6b SQLITE_CONSTRAINT_NOTNULL do_test notnull-2.6 { catchsql { @@ -272,7 +272,7 @@ do_test notnull-2.10 { UPDATE t1 SET e=null, a=b, b=a; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.e may not be NULL}} +} {1 {NOT NULL constraint failed: t1.e}} verify_ex_errcode notnull-2.10b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.0 { @@ -298,7 +298,7 @@ do_test notnull-3.2 { INSERT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-3.2b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.3 { catchsql { @@ -313,7 +313,7 @@ do_test notnull-3.4 { INSERT OR REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-3.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.5 { catchsql { @@ -321,7 +321,7 @@ do_test notnull-3.5 { INSERT OR ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-3.5b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.6 { catchsql { @@ -357,7 +357,7 @@ do_test notnull-3.10 { INSERT INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.b may not be NULL}} +} {1 {NOT NULL constraint failed: t1.b}} verify_ex_errcode notnull-3.10b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.11 { catchsql { @@ -400,7 +400,7 @@ do_test notnull-3.16 { INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } -} {1 {t1.c may not be NULL}} +} {1 {NOT NULL constraint failed: t1.c}} verify_ex_errcode notnull-3.16b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.17 { catchsql { @@ -408,7 +408,7 @@ do_test notnull-3.17 { INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } -} {1 {t1.d may not be NULL}} +} {1 {NOT NULL constraint failed: t1.d}} verify_ex_errcode notnull-3.17b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.18 { catchsql { @@ -430,7 +430,7 @@ do_test notnull-3.20 { INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,null); SELECT * FROM t1 order by a; } -} {1 {t1.e may not be NULL}} +} {1 {NOT NULL constraint failed: t1.e}} verify_ex_errcode notnull-3.20b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.21 { catchsql { @@ -447,7 +447,7 @@ do_test notnull-4.1 { UPDATE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-4.1b SQLITE_CONSTRAINT_NOTNULL do_test notnull-4.2 { catchsql { @@ -456,7 +456,7 @@ do_test notnull-4.2 { UPDATE OR REPLACE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-4.2b SQLITE_CONSTRAINT_NOTNULL do_test notnull-4.3 { catchsql { @@ -473,7 +473,7 @@ do_test notnull-4.4 { UPDATE OR ABORT t1 SET a=null; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.a may not be NULL}} +} {1 {NOT NULL constraint failed: t1.a}} verify_ex_errcode notnull-4.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-4.5 { catchsql { @@ -482,7 +482,7 @@ do_test notnull-4.5 { UPDATE t1 SET b=null; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.b may not be NULL}} +} {1 {NOT NULL constraint failed: t1.b}} verify_ex_errcode notnull-4.5b SQLITE_CONSTRAINT_NOTNULL do_test notnull-4.6 { catchsql { @@ -523,7 +523,7 @@ do_test notnull-4.10 { UPDATE t1 SET e=null, a=b, b=a; SELECT * FROM t1 ORDER BY a; } -} {1 {t1.e may not be NULL}} +} {1 {NOT NULL constraint failed: t1.e}} verify_ex_errcode notnull-4.10b SQLITE_CONSTRAINT_NOTNULL # Test that bug 29ab7be99f is fixed. @@ -542,7 +542,7 @@ do_test notnull-5.2 { INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 SELECT * FROM t2; } -} {1 {t1.b may not be NULL}} +} {1 {NOT NULL constraint failed: t1.b}} verify_ex_errcode notnull-5.2b SQLITE_CONSTRAINT_NOTNULL do_test notnull-5.3 { execsql { SELECT * FROM t1 } @@ -555,7 +555,7 @@ do_test notnull-5.4 { INSERT INTO t1 SELECT * FROM t2; COMMIT; } -} {1 {t1.b may not be NULL}} +} {1 {NOT NULL constraint failed: t1.b}} verify_ex_errcode notnull-5.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-5.5 { execsql { SELECT * FROM t1 } diff --git a/test/orderby1.test b/test/orderby1.test index f459fc8..e06c9f1 100644 --- a/test/orderby1.test +++ b/test/orderby1.test @@ -48,7 +48,7 @@ do_test 1.0 { } {} do_test 1.1a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} @@ -66,7 +66,7 @@ do_test 1.1b { # do_test 1.2a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} @@ -75,7 +75,7 @@ do_test 1.2a { do_test 1.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -85,13 +85,13 @@ do_test 1.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 1.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -101,55 +101,57 @@ db cache flush # do_test 1.4a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 1.4b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 1.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn } -} {~/ORDER BY/} ;# optimized out - +} {~/ORDER BY/} ;# ORDER BY suppressed due to uniqueness constraints do_test 1.5a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 1.5b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting do_test 1.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } -} {~/ORDER BY/} ;# optimized out +} {~/ORDER BY/} ;# ORDER BY suppressed due to uniqueness constraints do_test 1.6a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) + ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 1.6b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) + ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 1.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) + ORDER BY title DESC, tn DESC } -} {~/ORDER BY/} ;# ORDER BY optimized-out +} {~/ORDER BY/} ;# ORDER BY # Reconstruct the test data to use indices rather than integer primary keys. @@ -183,7 +185,7 @@ do_test 2.0 { } {} do_test 2.1a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} @@ -192,28 +194,28 @@ do_test 2.1a { do_test 2.1b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } -} {~/ORDER BY/} ;# ORDER BY optimized out +} {/ORDER BY/} ;# ORDER BY required because of missing aid term in ORDER BY do_test 2.1c { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn } } {one-a one-c two-a two-b three-a three-c} do_test 2.1d { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn } -} {~/ORDER BY/} ;# ORDER BY optimized out +} {/ORDER BY/} ;# ORDER BY required in this case # The same query with ORDER BY clause optimization disabled via + operators # should give exactly the same answer. # do_test 2.2a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} @@ -222,7 +224,7 @@ do_test 2.2a { do_test 2.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -232,13 +234,13 @@ do_test 2.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 2.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -248,55 +250,55 @@ db cache flush # do_test 2.4a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 2.4b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 2.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn } -} {~/ORDER BY/} ;# optimized out +} {/ORDER BY/} ;# separate sorting pass due to mixed DESC/ASC do_test 2.5a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 2.5b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting do_test 2.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } -} {~/ORDER BY/} ;# optimized out +} {/ORDER BY/} ;# separate sorting pass due to mixed ASC/DESC do_test 2.6a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 2.6b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 2.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC } -} {~/ORDER BY/} ;# ORDER BY optimized out +} {/ORDER BY/} ;# ORDER BY required # Generate another test dataset, but this time using mixed ASC/DESC indices. @@ -348,7 +350,7 @@ do_test 3.1b { # do_test 3.2a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} @@ -357,7 +359,7 @@ do_test 3.2a { do_test 3.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -367,13 +369,13 @@ do_test 3.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 3.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -383,38 +385,37 @@ db cache flush # do_test 3.4a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 3.4b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} ;# verify same order after sorting do_test 3.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } -} {~/ORDER BY/} ;# optimized out - +} {~/ORDER BY/} ;# ORDER BY suppressed by uniqueness constraints do_test 3.5a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 3.5b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 3.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC } -} {~/ORDER BY/} ;# optimzed out +} {~/ORDER BY/} ;# ORDER BY suppressed by uniqueness constraints do_test 3.6a { @@ -424,7 +425,8 @@ do_test 3.6a { } {three-a three-c two-a two-b one-a one-c} do_test 3.6b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album CROSS JOIN track USING (aid) + ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 3.6c { @@ -434,5 +436,50 @@ do_test 3.6c { } } {~/ORDER BY/} ;# inverted ASC/DESC is optimized out +# Ticket 5ed1772895bf3deeab78c5e3519b1da9165c541b (2013-06-04) +# Incorrect ORDER BY on an indexed JOIN +# +do_test 4.0 { + db eval { + CREATE TABLE t41(a INT UNIQUE NOT NULL, b INT NOT NULL); + CREATE INDEX t41ba ON t41(b,a); + CREATE TABLE t42(x INT NOT NULL REFERENCES t41(a), y INT NOT NULL); + CREATE UNIQUE INDEX t42xy ON t42(x,y); + INSERT INTO t41 VALUES(1,1),(3,1); + INSERT INTO t42 VALUES(1,13),(1,15),(3,14),(3,16); + + SELECT b, y FROM t41 CROSS JOIN t42 ON x=a ORDER BY b, y; + } +} {1 13 1 14 1 15 1 16} + +# No sorting of queries that omit the FROM clause. +# +do_execsql_test 5.0 { + EXPLAIN QUERY PLAN SELECT 5 ORDER BY 1 +} {} +do_execsql_test 5.1 { + EXPLAIN QUERY PLAN SELECT 5 UNION ALL SELECT 3 ORDER BY 1 +} {~/B-TREE/} +do_execsql_test 5.2 { + SELECT 5 UNION ALL SELECT 3 ORDER BY 1 +} {3 5} + +# The following test (originally derived from a single test within fuzz.test) +# verifies that a PseudoTable cursor is not closed prematurely in a deeply +# nested query. This test caused a segfault on 3.8.5 beta. +# +do_execsql_test 6.0 { + CREATE TABLE abc(a, b, c); + INSERT INTO abc VALUES(1, 2, 3); + INSERT INTO abc VALUES(4, 5, 6); + INSERT INTO abc VALUES(7, 8, 9); + SELECT ( + SELECT 'hardware' FROM ( + SELECT 'software' ORDER BY 'firmware' ASC, 'sportswear' DESC + ) GROUP BY 1 HAVING length(b) + ) + FROM abc; +} {hardware hardware hardware} + finish_test diff --git a/test/orderby5.test b/test/orderby5.test new file mode 100644 index 0000000..c9cce70 --- /dev/null +++ b/test/orderby5.test @@ -0,0 +1,130 @@ +# 2013-06-14 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing that the optimizations that disable +# ORDER BY clauses work correctly +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix orderby5 + +# Generate test data for a join. Verify that the join gets the +# correct answer. +# +do_execsql_test 1.1 { + CREATE TABLE t1(a,b,c); + CREATE INDEX t1bc ON t1(b,c); + + EXPLAIN QUERY PLAN + SELECT DISTINCT a, b, c FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.2.1 { + EXPLAIN QUERY PLAN + SELECT DISTINCT a, c, b FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.2.2 { + EXPLAIN QUERY PLAN + SELECT DISTINCT a, c, b FROM t1 WHERE a='xyz' COLLATE nocase; +} {/B-TREE/} +do_execsql_test 1.2.3 { + EXPLAIN QUERY PLAN + SELECT DISTINCT a COLLATE nocase, c, b FROM t1 WHERE a='xyz'; +} {/B-TREE/} +do_execsql_test 1.2.4 { + EXPLAIN QUERY PLAN + SELECT DISTINCT a COLLATE nocase, c, b FROM t1 WHERE a='xyz' COLLATE nocase; +} {~/B-TREE/} +do_execsql_test 1.3 { + EXPLAIN QUERY PLAN + SELECT DISTINCT b, a, c FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.4 { + EXPLAIN QUERY PLAN + SELECT DISTINCT b, c, a FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.5 { + EXPLAIN QUERY PLAN + SELECT DISTINCT c, a, b FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.6 { + EXPLAIN QUERY PLAN + SELECT DISTINCT c, b, a FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.7 { + EXPLAIN QUERY PLAN + SELECT DISTINCT c, b, a FROM t1 WHERE +a=0; +} {/B-TREE/} + +# In some cases, it is faster to do repeated index lookups than it is to +# sort. But in other cases, it is faster to sort than to do repeated index +# lookups. +# +do_execsql_test 2.1a { + CREATE TABLE t2(a,b,c); + CREATE INDEX t2bc ON t2(b,c); + ANALYZE; + INSERT INTO sqlite_stat1 VALUES('t1','t1bc','1000000 10 9'); + INSERT INTO sqlite_stat1 VALUES('t2','t2bc','100 10 5'); + ANALYZE sqlite_master; + + EXPLAIN QUERY PLAN + SELECT * FROM t2 WHERE a=0 ORDER BY a, b, c; +} {~/B-TREE/} + +do_execsql_test 2.1b { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE likelihood(a=0, 0.05) ORDER BY a, b, c; +} {/B-TREE/} + +do_execsql_test 2.2 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c; +} {/B-TREE/} +do_execsql_test 2.3 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY b, a, c; +} {~/B-TREE/} +do_execsql_test 2.4 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY b, c, a; +} {~/B-TREE/} +do_execsql_test 2.5 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY a, c, b; +} {/B-TREE/} +do_execsql_test 2.6 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY c, a, b; +} {/B-TREE/} +do_execsql_test 2.7 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY c, b, a; +} {/B-TREE/} + + +do_execsql_test 3.0 { + CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c, d, e, f); + CREATE INDEX t3bcde ON t3(b, c, d, e); + EXPLAIN QUERY PLAN + SELECT a FROM t3 WHERE b=2 AND c=3 ORDER BY d DESC, e DESC, b, c, a DESC; +} {~/B-TREE/} +do_execsql_test 3.1 { + DROP TABLE t3; + CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c, d, e, f) WITHOUT rowid; + CREATE INDEX t3bcde ON t3(b, c, d, e); + EXPLAIN QUERY PLAN + SELECT a FROM t3 WHERE b=2 AND c=3 ORDER BY d DESC, e DESC, b, c, a DESC; +} {~/B-TREE/} + + +finish_test diff --git a/test/orderby6.test b/test/orderby6.test new file mode 100644 index 0000000..403250d --- /dev/null +++ b/test/orderby6.test @@ -0,0 +1,183 @@ +# 2014-03-21 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing that the block-sort optimization. +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix orderby6 + +# Run all tests twice. Once with a normal table and a second time +# with a WITHOUT ROWID table +# +foreach {tn rowidclause} {1 {} 2 {WITHOUT ROWID}} { + + # Construct a table with 1000 rows and a split primary key + # + reset_db + do_test $tn.1 { + db eval "CREATE TABLE t1(a,b,c,PRIMARY KEY(b,c)) $rowidclause;" + db eval { + WITH RECURSIVE + cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000) + INSERT INTO t1 SELECT x, x%40, x/40 FROM cnt; + } + } {} + + # Run various ORDER BY queries that can benefit from block-sort. + # Compare the output to the same output using a full-sort enforced + # by adding + to each term of the ORDER BY clause. + # + do_execsql_test $tn.2 { + SELECT b,a,c FROM t1 ORDER BY b,a,c; + } [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+a,+c}] + do_execsql_test $tn.3 { + SELECT b,a,c FROM t1 ORDER BY b,c DESC,a; + } [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+c DESC,+a}] + do_execsql_test $tn.4 { + SELECT b,a,c FROM t1 ORDER BY b DESC,c,a; + } [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+c,+a}] + do_execsql_test $tn.5 { + SELECT b,a,c FROM t1 ORDER BY b DESC,a,c; + } [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+a,+c}] + + # LIMIT and OFFSET clauses on block-sort queries. + # + do_execsql_test $tn.11 { + SELECT a FROM t1 ORDER BY b, a LIMIT 10 OFFSET 20; + } {840 880 920 960 1000 1 41 81 121 161} + do_execsql_test $tn.11x { + SELECT a FROM t1 ORDER BY +b, a LIMIT 10 OFFSET 20; + } {840 880 920 960 1000 1 41 81 121 161} + + do_execsql_test $tn.12 { + SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 20; + } {839 879 919 959 999 38 78 118 158 198} + do_execsql_test $tn.12 { + SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 20; + } {839 879 919 959 999 38 78 118 158 198} + + do_execsql_test $tn.13 { + SELECT a FROM t1 ORDER BY b, a DESC LIMIT 10 OFFSET 45; + } {161 121 81 41 1 962 922 882 842 802} + do_execsql_test $tn.13x { + SELECT a FROM t1 ORDER BY +b, a DESC LIMIT 10 OFFSET 45; + } {161 121 81 41 1 962 922 882 842 802} + + do_execsql_test $tn.14 { + SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 45; + } {838 878 918 958 998 37 77 117 157 197} + do_execsql_test $tn.14x { + SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 45; + } {838 878 918 958 998 37 77 117 157 197} + + # Many test cases where the LIMIT+OFFSET window is in various + # alignments with block-sort boundaries. + # + foreach {tx limit offset orderby} { + 1 10 24 {+b,+a} + 2 10 25 {+b,+a} + 3 10 26 {+b,+a} + 4 10 39 {+b,+a} + 5 10 40 {+b,+a} + 6 10 41 {+b,+a} + 7 27 24 {+b,+a} + 8 27 49 {+b,+a} + 11 10 24 {+b DESC,+a} + 12 10 25 {+b DESC,+a} + 13 10 26 {+b DESC,+a} + 14 10 39 {+b DESC,+a} + 15 10 40 {+b DESC,+a} + 16 10 41 {+b DESC,+a} + 17 27 24 {+b DESC,+a} + 18 27 49 {+b DESC,+a} + 21 10 24 {+b,+a DESC} + 22 10 25 {+b,+a DESC} + 23 10 26 {+b,+a DESC} + 24 10 39 {+b,+a DESC} + 25 10 40 {+b,+a DESC} + 26 10 41 {+b,+a DESC} + 27 27 24 {+b,+a DESC} + 28 27 49 {+b,+a DESC} + 31 10 24 {+b DESC,+a DESC} + 32 10 25 {+b DESC,+a DESC} + 33 10 26 {+b DESC,+a DESC} + 34 10 39 {+b DESC,+a DESC} + 35 10 40 {+b DESC,+a DESC} + 36 10 41 {+b DESC,+a DESC} + 37 27 24 {+b DESC,+a DESC} + 38 27 49 {+b DESC,+a DESC} + } { + set sql1 "SELECT a FROM t1 ORDER BY $orderby LIMIT $limit OFFSET $offset;" + set sql2 [string map {+ {}} $sql1] + # puts $sql2\n$sql1\n[db eval $sql2] + do_test $tn.21.$tx {db eval $::sql2} [db eval $sql1] + } + + ######################################################################## + # A second test table, t2, has many columns open to sorting. + do_test $tn.31 { + db eval "CREATE TABLE t2(a,b,c,d,e,f,PRIMARY KEY(b,c,d,e,f)) $rowidclause;" + db eval { + WITH RECURSIVE + cnt(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM cnt WHERE x<242) + INSERT INTO t2 SELECT x, x%3, (x/3)%3, (x/9)%3, (x/27)%3, (x/81)%3 + FROM cnt; + } + } {} + + do_execsql_test $tn.32 { + SELECT a FROM t2 ORDER BY b,c,d,e,f; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}] + do_execsql_test $tn.33 { + SELECT a FROM t2 ORDER BY b,c,d,e,+f; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}] + do_execsql_test $tn.34 { + SELECT a FROM t2 ORDER BY b,c,d,+e,+f; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}] + do_execsql_test $tn.35 { + SELECT a FROM t2 ORDER BY b,c,+d,+e,+f; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}] + do_execsql_test $tn.36 { + SELECT a FROM t2 ORDER BY b,+c,+d,+e,+f; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}] + + do_execsql_test $tn.37 { + SELECT a FROM t2 ORDER BY b,c,d,e,f DESC; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC;}] + do_execsql_test $tn.38 { + SELECT a FROM t2 ORDER BY b,c,d,e DESC,f; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e DESC,+f;}] + do_execsql_test $tn.39 { + SELECT a FROM t2 ORDER BY b,c,d DESC,e,f; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d DESC,+e,+f;}] + do_execsql_test $tn.40 { + SELECT a FROM t2 ORDER BY b,c DESC,d,e,f; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c DESC,+d,+e,+f;}] + do_execsql_test $tn.41 { + SELECT a FROM t2 ORDER BY b DESC,c,d,e,f; + } [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c,+d,+e,+f;}] + + do_execsql_test $tn.42 { + SELECT a FROM t2 ORDER BY b DESC,c DESC,d,e,f LIMIT 31; + } [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c DESC,+d,+e,+f LIMIT 31}] + do_execsql_test $tn.43 { + SELECT a FROM t2 ORDER BY b,c,d,e,f DESC LIMIT 8 OFFSET 7; + } [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC LIMIT 8 OFFSET 7}] + + +} + + + +finish_test diff --git a/test/orderby7.test b/test/orderby7.test new file mode 100644 index 0000000..8c5fc9a --- /dev/null +++ b/test/orderby7.test @@ -0,0 +1,106 @@ +# 2014-04-25 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing ORDER BY optimizations on joins +# that involve virtual tables. +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix orderby7 + +ifcapable !fts3 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE fts USING fts3(content TEXT); + INSERT INTO fts(rowid,content) + VALUES(1,'this is a test of the fts3 virtual'), + (2,'table used as part of a join together'), + (3,'with the DISTINCT keyword. There was'), + (4,'a bug at one time (2013-06 through 2014-04)'), + (5,'that prevented this from working correctly.'), + (11,'a row that occurs twice'), + (12,'a row that occurs twice'); + + CREATE TABLE t1(x TEXT PRIMARY KEY, y); + INSERT OR IGNORE INTO t1 SELECT content, rowid+100 FROM fts; +} {} +do_execsql_test 1.1 { + SELECT DISTINCT fts.rowid, t1.y + FROM fts, t1 + WHERE fts MATCH 'that twice' + AND content=x + ORDER BY y; +} {11 111 12 111} +do_execsql_test 1.2 { + SELECT DISTINCT fts.rowid, t1.x + FROM fts, t1 + WHERE fts MATCH 'that twice' + AND content=x + ORDER BY 1; +} {11 {a row that occurs twice} 12 {a row that occurs twice}} +do_execsql_test 1.3 { + SELECT DISTINCT t1.x + FROM fts, t1 + WHERE fts MATCH 'that twice' + AND content=x + ORDER BY 1; +} {{a row that occurs twice}} +do_execsql_test 1.4 { + SELECT t1.x + FROM fts, t1 + WHERE fts MATCH 'that twice' + AND content=x + ORDER BY 1; +} {{a row that occurs twice} {a row that occurs twice}} +do_execsql_test 1.5 { + SELECT DISTINCT t1.x + FROM fts, t1 + WHERE fts MATCH 'that twice' + AND content=x; +} {{a row that occurs twice}} +do_execsql_test 1.6 { + SELECT t1.x + FROM fts, t1 + WHERE fts MATCH 'that twice' + AND content=x; +} {{a row that occurs twice} {a row that occurs twice}} + +do_execsql_test 2.1 { + SELECT DISTINCT t1.x + FROM fts, t1 + WHERE fts.rowid=11 + AND content=x + ORDER BY fts.rowid; +} {{a row that occurs twice}} +do_execsql_test 2.2 { + SELECT DISTINCT t1.* + FROM fts, t1 + WHERE fts.rowid=11 + AND content=x + ORDER BY fts.rowid; +} {{a row that occurs twice} 111} +do_execsql_test 2.3 { + SELECT DISTINCT t1.* + FROM fts, t1 + WHERE fts.rowid=11 + AND content=x + ORDER BY t1.y +} {{a row that occurs twice} 111} + + + + +finish_test diff --git a/test/pager1.test b/test/pager1.test index 72e4780..005b356 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -271,7 +271,7 @@ do_execsql_test pager1-3.1.2 { } {3 0} do_catchsql_test pager1-3.1.3 { INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1 -} {1 {constraint failed}} +} {1 {CHECK constraint failed: counter}} do_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0} do_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3} do_execsql_test pager1-3.6 { COMMIT } {} @@ -1703,7 +1703,7 @@ do_catchsql_test pager1-14.1.4 { BEGIN; INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; -} {1 {PRIMARY KEY must be unique}} +} {1 {UNIQUE constraint failed: t1.rowid}} do_execsql_test pager1-14.1.5 { COMMIT; SELECT * FROM t1; @@ -2815,4 +2815,3 @@ do_test 43.3 { } {0 1 0} finish_test - diff --git a/test/pager4.test b/test/pager4.test new file mode 100644 index 0000000..2cf73d1 --- /dev/null +++ b/test/pager4.test @@ -0,0 +1,99 @@ +# 2013-12-06 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Tests for the SQLITE_READONLY_DBMOVED error condition: the database file +# is unlinked or renamed out from under SQLite. +# + +if {$tcl_platform(platform)!="unix"} return + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +if {[permutation]=="inmemory_journal"} { + finish_test + return +} + +# Create a database file for testing +# +do_execsql_test pager4-1.1 { + CREATE TABLE t1(a,b,c); + INSERT INTO t1 VALUES(673,'stone','philips'); + SELECT * FROM t1; +} {673 stone philips} + +# After renaming the database file while it is open, one can still +# read from the database, but writing returns a READONLY error. +# +file delete -force test-xyz.db +file rename test.db test-xyz.db +do_catchsql_test pager4-1.2 { + SELECT * FROM t1; +} {0 {673 stone philips}} +do_catchsql_test pager4-1.3 { + UPDATE t1 SET a=537; +} {1 {attempt to write a readonly database}} + +# Creating a different database file with the same name of the original +# is detected and still leaves the database read-only. +# +sqlite3 db2 test.db +db2 eval {CREATE TABLE t2(x,y,z)} +do_catchsql_test pager4-1.4 { + UPDATE t1 SET a=948; +} {1 {attempt to write a readonly database}} + +# Changing the name back clears the READONLY error +# +db2 close +file delete -force test.db +file rename test-xyz.db test.db +do_catchsql_test pager4-1.5 { + SELECT * FROM t1; +} {0 {673 stone philips}} +do_catchsql_test pager4-1.6 { + UPDATE t1 SET a=537; + SELECT * FROM t1; +} {0 {537 stone philips}} + +# We can write to a renamed database if journal_mode=OFF or +# journal_mode=MEMORY. +# +file rename test.db test-xyz.db +do_catchsql_test pager4-1.7 { + PRAGMA journal_mode=OFF; + UPDATE t1 SET a=107; + SELECT * FROM t1; +} {0 {off 107 stone philips}} +do_catchsql_test pager4-1.8 { + PRAGMA journal_mode=MEMORY; + UPDATE t1 SET b='magpie'; + SELECT * FROM t1; +} {0 {memory 107 magpie philips}} + +# Any other journal mode gives a READONLY error +# +do_catchsql_test pager4-1.9 { + PRAGMA journal_mode=DELETE; + UPDATE t1 SET c='jaguar'; +} {1 {attempt to write a readonly database}} +do_catchsql_test pager4-1.10 { + PRAGMA journal_mode=TRUNCATE; + UPDATE t1 SET c='jaguar'; +} {1 {attempt to write a readonly database}} +do_catchsql_test pager4-1.11 { + PRAGMA journal_mode=PERSIST; + UPDATE t1 SET c='jaguar'; +} {1 {attempt to write a readonly database}} + + +finish_test diff --git a/test/pagerfault.test b/test/pagerfault.test index 23754fa..c0f5de6 100644 --- a/test/pagerfault.test +++ b/test/pagerfault.test @@ -1544,6 +1544,6 @@ do_faultsim_test pagerfault-36 -prep { sqlite3_shutdown sqlite3_config_uri 0 +sqlite3_initialize finish_test - diff --git a/test/pagerfault2.test b/test/pagerfault2.test index 6cdb99a..7f6c995 100644 --- a/test/pagerfault2.test +++ b/test/pagerfault2.test @@ -96,4 +96,3 @@ do_faultsim_test pagerfault2-2 -faults oom-transient -prep { sqlite3_memdebug_vfs_oom_test 1 finish_test - diff --git a/test/pagerfault3.test b/test/pagerfault3.test index 3d192e6..a4301cd 100644 --- a/test/pagerfault3.test +++ b/test/pagerfault3.test @@ -61,4 +61,3 @@ do_faultsim_test pagerfault3-1 -faults ioerr-transient -prep { } finish_test - diff --git a/test/pcache.test b/test/pcache.test index 5dc3059..0766fce 100644 --- a/test/pcache.test +++ b/test/pcache.test @@ -44,6 +44,7 @@ do_test pcache-1.2 { execsql { PRAGMA cache_size=12; PRAGMA auto_vacuum=0; + PRAGMA mmap_size=0; } pcache_stats } {current 1 max 12 min 10 recyclable 1} diff --git a/test/percentile.test b/test/percentile.test new file mode 100644 index 0000000..9d471df --- /dev/null +++ b/test/percentile.test @@ -0,0 +1,209 @@ +# 2013-05-28 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is percentile.c extension +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Basic test of the percentile() function. +# +do_test percentile-1.0 { + load_static_extension db percentile + execsql { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1),(4),(6),(7),(8),(9),(11),(11),(11); + } + execsql {SELECT percentile(x,0) FROM t1} +} {1.0} +foreach {in out} { + 100 11.0 + 50 8.0 + 12.5 4.0 + 15 4.4 + 20 5.2 + 80 11.0 + 89 11.0 +} { + do_test percentile-1.1.$in { + execsql {SELECT percentile(x,$in) FROM t1} + } $out +} + +# Add some NULL values. +# +do_test percentile-1.2 { + execsql {INSERT INTO t1 VALUES(NULL),(NULL);} +} {} +foreach {in out} { + 100 11.0 + 50 8.0 + 12.5 4.0 + 15 4.4 + 20 5.2 + 80 11.0 + 89 11.0 +} { + do_test percentile-1.3.$in { + execsql {SELECT percentile(x,$in) FROM t1} + } $out +} + +# The second argument to percentile can change some, but not much. +# +do_test percentile-1.4 { + catchsql {SELECT round(percentile(x, 15+0.000001*rowid),1) FROM t1} +} {0 4.4} +do_test percentile-1.5 { + catchsql {SELECT round(percentile(x, 15+0.1*rowid),1) FROM t1} +} {1 {2nd argument to percentile() is not the same for all input rows}} + +# Input values in a random order +# +do_test percentile-1.6 { + execsql { + CREATE TABLE t2(x); + INSERT INTO t2 SELECT x+0.0 FROM t1 ORDER BY random(); + } +} {} +foreach {in out} { + 100 11.0 + 50 8.0 + 12.5 4.0 + 15 4.4 + 20 5.2 + 80 11.0 + 89 11.0 +} { + do_test percentile-1.7.$in { + execsql {SELECT percentile(x,$in) FROM t2} + } $out +} + +# Wrong number of arguments +# +do_test percentile-1.8 { + catchsql {SELECT percentile(x,0,1) FROM t1} +} {1 {wrong number of arguments to function percentile()}} +do_test percentile-1.9 { + catchsql {SELECT percentile(x) FROM t1} +} {1 {wrong number of arguments to function percentile()}} + +# Second argument must be numeric +# +do_test percentile-1.10 { + catchsql {SELECT percentile(x,null) FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} +do_test percentile-1.11 { + catchsql {SELECT percentile(x,'fifty') FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} +do_test percentile-1.12 { + catchsql {SELECT percentile(x,x'3530') FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} + +# Second argument is out of range +# +do_test percentile-1.13 { + catchsql {SELECT percentile(x,-0.0000001) FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} +do_test percentile-1.14 { + catchsql {SELECT percentile(x,100.0000001) FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} + +# First argument is not NULL and is not NUMERIC +# +do_test percentile-1.15 { + catchsql { + BEGIN; + UPDATE t1 SET x='50' WHERE x IS NULL; + SELECT percentile(x, 50) FROM t1; + } +} {1 {1st argument to percentile() is not numeric}} +do_test percentile-1.16 { + catchsql { + ROLLBACK; + BEGIN; + UPDATE t1 SET x=x'3530' WHERE x IS NULL; + SELECT percentile(x, 50) FROM t1; + } +} {1 {1st argument to percentile() is not numeric}} +do_test percentile-1.17 { + catchsql { + ROLLBACK; + SELECT percentile(x, 50) FROM t1; + } +} {0 8.0} + +# No non-NULL entries. +# +do_test percentile-1.18 { + execsql { + UPDATE t1 SET x=NULL; + SELECT ifnull(percentile(x, 50),'NULL') FROM t1 + } +} {NULL} + +# Exactly one non-NULL entry +# +do_test percentile-1.19 { + execsql { + UPDATE t1 SET x=12345 WHERE rowid=5; + SELECT percentile(x, 0), percentile(x, 50), percentile(x,100) FROM t1 + } +} {12345.0 12345.0 12345.0} + +# Infinity as an input +# +do_test percentile-1.20 { + catchsql { + DELETE FROM t1; + INSERT INTO t1 SELECT x+0.0 FROM t2; + UPDATE t1 SET x=1.0e300*1.0e300 WHERE rowid=5; + SELECT percentile(x,50) from t1; + } +} {1 {Inf input to percentile()}} +do_test percentile-1.21 { + catchsql { + UPDATE t1 SET x=-1.0e300*1.0e300 WHERE rowid=5; + SELECT percentile(x,50) from t1; + } +} {1 {Inf input to percentile()}} + +# Million-row Inputs +# +ifcapable vtab { + do_test percentile-2.0 { + load_static_extension db wholenumber + execsql { + CREATE VIRTUAL TABLE nums USING wholenumber; + CREATE TABLE t3(x); + INSERT INTO t3 SELECT value-1 FROM nums WHERE value BETWEEN 1 AND 500000; + INSERT INTO t3 SELECT value*10 FROM nums + WHERE value BETWEEN 500000 AND 999999; + SELECT count(*) FROM t3; + } + } {1000000} + foreach {in out} { + 0 0.0 + 100 9999990.0 + 50 2749999.5 + 10 99999.9 + } { + do_test percentile-2.1.$in { + execsql { + SELECT percentile(x, $in) from t3; + } + } $out + } +} + +finish_test diff --git a/test/permutations.test b/test/permutations.test index bc3ceb8..c3f4ddf 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -112,6 +112,7 @@ set allquicktests [test_set $alltests -exclude { incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test vtab_err.test walslow.test walcrash.test walcrash3.test walthread.test rtree3.test indexfault.test securedel2.test + fts4growth.test fts4growth2.test }] if {[info exists ::env(QUICKTEST_INCLUDE)]} { set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)] @@ -157,6 +158,28 @@ test_suite "valgrind" -prefix "" -description { unset -nocomplain ::G(valgrind) } +test_suite "valgrind-nolookaside" -prefix "" -description { + Run the "veryquick" test suite with a couple of multi-process tests (that + fail under valgrind) omitted. +} -files [ + test_set $allquicktests -exclude *malloc* *ioerr* *fault* wal.test atof1.test +] -initialize { + set ::G(valgrind) 1 + catch {db close} + sqlite3_shutdown + sqlite3_config_lookaside 0 0 + sqlite3_initialize + autoinstall_test_functions +} -shutdown { + catch {db close} + sqlite3_shutdown + sqlite3_config_lookaside 100 500 + sqlite3_initialize + autoinstall_test_functions + unset -nocomplain ::G(valgrind) +} + + test_suite "quick" -prefix "" -description { Quick test suite. Runs in around 10 minutes on a workstation. } -files [ @@ -194,7 +217,9 @@ test_suite "fts3" -prefix "" -description { fts4aa.test fts4content.test fts3conf.test fts3prefix.test fts3fault2.test fts3corrupt.test fts3corrupt2.test fts3first.test fts4langid.test fts4merge.test - fts4check.test fts4unicode.test + fts4check.test fts4unicode.test fts4noti.test + fts3varint.test + fts4growth.test fts4growth2.test } test_suite "nofaultsim" -prefix "" -description { @@ -213,6 +238,93 @@ test_suite "nofaultsim" -prefix "" -description { unset -nocomplain ::G(valgrind) } +test_suite "queryplanner" -prefix "" -description { + Tests of the query planner and query optimizer +} -files { + alter2.test alter3.test alter4.test alter.test analyze3.test + analyze4.test analyze5.test analyze6.test analyze7.test analyze8.test + analyze.test attach2.test attach3.test attach4.test + attach.test autoinc.test autoindex1.test between.test cast.test + check.test closure01.test coalesce.test collate1.test collate2.test + collate3.test collate4.test collate5.test collate6.test collate7.test + collate8.test collate9.test collateA.test colmeta.test colname.test + conflict.test count.test coveridxscan.test createtab.test cse.test + date.test dbstatus2.test dbstatus.test default.test delete2.test + delete3.test delete.test descidx1.test descidx2.test descidx3.test + distinctagg.test distinct.test e_createtable.test e_delete.test + e_droptrigger.test e_dropview.test e_expr.test e_insert.test + eqp.test e_reindex.test e_resolve.test e_select2.test e_select.test + e_update.test exists.test expr.test fkey1.test fkey2.test fkey3.test + fkey4.test fkey5.test func2.test func3.test func.test + in3.test in4.test in5.test index2.test index3.test + index4.test index5.test indexedby.test index.test + insert2.test insert3.test insert4.test insert5.test insert.test + instr.test in.test intpkey.test join2.test join3.test join4.test + join5.test join6.test join.test like2.test like.test limit.test + minmax2.test minmax3.test minmax4.test minmax.test misc1.test misc2.test + misc3.test misc4.test misc5.test misc6.test misc7.test orderby1.test + orderby2.test orderby3.test orderby4.test randexpr1.test regexp1.test + reindex.test rowhash.test rowid.test schema2.test schema3.test + schema4.test schema5.test schema.test + select1.test select2.test select3.test select4.test select5.test + select6.test select7.test select8.test select9.test selectA.test + selectB.test selectC.test selectD.test selectE.test sidedelete.test + sort.test spellfix.test subquery2.test subquery.test subselect.test + substr.test tkt-02a8e81d44.test tkt1435.test tkt1443.test tkt1444.test + tkt1449.test tkt1473.test tkt1501.test tkt1512.test tkt1514.test + tkt1536.test tkt1537.test tkt1567.test tkt1644.test tkt1667.test + tkt1873.test tkt2141.test tkt2192.test tkt2213.test tkt2251.test + tkt2285.test tkt2332.test tkt2339.test tkt2391.test tkt2409.test + tkt2450.test tkt2565.test tkt2640.test tkt2643.test tkt2686.test + tkt-26ff0c2d1e.test tkt2767.test tkt2817.test tkt2820.test tkt2822.test + tkt2832.test tkt2854.test tkt2920.test tkt2927.test tkt2942.test + tkt-2a5629202f.test tkt-2d1a5c67d.test tkt-2ea2425d34.test tkt3080.test + tkt3093.test tkt3121.test tkt-31338dca7e.test tkt-313723c356.test + tkt3201.test tkt3292.test tkt3298.test tkt3334.test tkt3346.test + tkt3357.test tkt3419.test tkt3424.test tkt3442.test tkt3457.test + tkt3461.test tkt3493.test tkt3508.test tkt3522.test tkt3527.test + tkt3541.test tkt3554.test tkt3581.test tkt35xx.test tkt3630.test + tkt3718.test tkt3731.test tkt3757.test tkt3761.test tkt3762.test + tkt3773.test tkt3791.test tkt3793.test tkt3810.test tkt3824.test + tkt3832.test tkt3838.test tkt3841.test tkt-385a5b56b9.test tkt3871.test + tkt3879.test tkt-38cb5df375.test tkt3911.test tkt3918.test tkt3922.test + tkt3929.test tkt3935.test tkt3992.test tkt3997.test tkt-3998683a16.test + tkt-3a77c9714e.test tkt-3fe897352e.test tkt4018.test tkt-4a03edc4c8.test + tkt-4dd95f6943.test tkt-54844eea3f.test tkt-5d863f876e.test + tkt-5e10420e8d.test tkt-5ee23731f.test tkt-6bfb98dfc0.test + tkt-752e1646fc.test tkt-78e04e52ea.test tkt-7a31705a7e6.test + tkt-7bbfb7d442.test tkt-80ba201079.test tkt-80e031a00f.test + tkt-8454a207b9.test tkt-91e2e8ba6f.test tkt-94c04eaadb.test + tkt-9d68c883.test tkt-a7b7803e.test tkt-b1d3a2e531.test + tkt-b351d95f9.test tkt-b72787b1.test tkt-bd484a090c.test + tkt-bdc6bbbb38.test tkt-c48d99d690.test tkt-cbd054fa6b.test + tkt-d11f09d36e.test tkt-d635236375.test tkt-d82e3f3721.test + tkt-f3e5abed55.test tkt-f777251dc7a.test tkt-f7b4edec.test + tkt-f973c7ac31.test tkt-fa7bf5ec.test tkt-fc62af4523.test + tkt-fc7bd6358f.test trigger1.test trigger2.test trigger3.test + trigger4.test trigger5.test trigger6.test trigger7.test trigger8.test + trigger9.test triggerA.test triggerB.test triggerC.test triggerD.test + types2.test types3.test types.test unique.test unordered.test + update.test view.test vtab1.test vtab2.test vtab3.test vtab4.test + vtab5.test vtab6.test vtab7.test vtab8.test vtab9.test vtab_alter.test + vtabA.test vtabB.test vtabC.test vtabD.test vtabE.test + vtabF.test where2.test where3.test where4.test where5.test where6.test + where7.test where8m.test where8.test where9.test whereA.test whereB.test + whereC.test whereD.test whereE.test whereF.test wherelimit.test + where.test +} + +test_suite "vfslog" -prefix "" -description { + "Vfslog" quick test suite. Like "veryquick" except does not omits + a few tests that do not work with a version 1 VFS. And the quota* tests, + which do not work with a VFS that uses the pVfs argument passed to + sqlite3_vfs methods. +} -files [ + test_set $allquicktests -exclude *malloc* *ioerr* *fault* oserror.test \ + pager1.test syscall.test sysfault.test tkt3457.test quota* superlock* \ + wal* mmap* +] + lappend ::testsuitelist xxx #------------------------------------------------------------------------- # Define the coverage related test suites: @@ -235,6 +347,14 @@ test_suite "coverage-pager" -description { walfault.test walbak.test journal2.test tkt-9d68c883.test } +test_suite "coverage-analyze" -description { + Coverage tests for file analyze.c. +} -files { + analyze3.test analyze4.test analyze5.test analyze6.test + analyze7.test analyze8.test analyze9.test analyzeA.test + analyze.test analyzeB.test mallocA.test +} + lappend ::testsuitelist xxx #------------------------------------------------------------------------- @@ -424,6 +544,8 @@ test_suite "utf16" -description { pragma encoding = 'UTF-16' } -files { alter.test alter3.test + analyze.test analyze3.test analyze4.test analyze5.test analyze6.test + analyze7.test analyze8.test analyze9.test analyzeA.test analyzeB.test auth.test bind.test blob.test capi2.test capi3.test collate1.test collate2.test collate3.test collate4.test collate5.test collate6.test conflict.test date.test delete.test expr.test fkey1.test func.test @@ -544,7 +666,7 @@ test_suite "inmemory_journal" -description { ioerr.test ioerr2.test ioerr3.test ioerr4.test ioerr5.test vacuum3.test incrblob_err.test diskfull.test backup_ioerr.test e_fts3.test fts3cov.test fts3malloc.test fts3rnd.test - fts3snippet.test + fts3snippet.test mmapfault.test # Exclude test scripts that use tcl IO to access journal files or count # the number of fsync() calls. diff --git a/test/pragma.test b/test/pragma.test index a6d198e..539d867 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -285,31 +285,31 @@ ifcapable attach { db close sqlite3 db test.db execsql {PRAGMA integrity_check} - } {{rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2}} + } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_test pragma-3.3 { execsql {PRAGMA integrity_check=1} - } {{rowid 1 missing from index i2}} + } {{row 1 missing from index i2}} do_test pragma-3.4 { execsql { ATTACH DATABASE 'test.db' AS t2; PRAGMA integrity_check } - } {{rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2}} + } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_test pragma-3.5 { execsql { PRAGMA integrity_check=4 } - } {{rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2}} + } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2}} do_test pragma-3.6 { execsql { PRAGMA integrity_check=xyz } - } {{rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2}} + } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_test pragma-3.7 { execsql { PRAGMA integrity_check=0 } - } {{rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2}} + } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} # Add additional corruption by appending unused pages to the end of # the database file testerr.db @@ -344,7 +344,7 @@ ifcapable attach { } {{*** in database t2 *** Page 4 is never used Page 5 is never used -Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2}} +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_test pragma-3.10 { execsql { PRAGMA integrity_check=1 @@ -358,7 +358,7 @@ Page 4 is never used}} } {{*** in database t2 *** Page 4 is never used Page 5 is never used -Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 missing from index i2}} +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2}} do_test pragma-3.12 { execsql { PRAGMA integrity_check=4 @@ -366,7 +366,7 @@ Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 missing from inde } {{*** in database t2 *** Page 4 is never used Page 5 is never used -Page 6 is never used} {rowid 1 missing from index i2}} +Page 6 is never used} {row 1 missing from index i2}} do_test pragma-3.13 { execsql { PRAGMA integrity_check=3 @@ -390,10 +390,10 @@ Page 5 is never used}} } {{*** in database t2 *** Page 4 is never used Page 5 is never used -Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** Page 4 is never used Page 5 is never used -Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2}} +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_test pragma-3.16 { execsql { PRAGMA integrity_check(10) @@ -401,10 +401,10 @@ Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 missing from inde } {{*** in database t2 *** Page 4 is never used Page 5 is never used -Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** Page 4 is never used Page 5 is never used -Page 6 is never used} {rowid 1 missing from index i2}} +Page 6 is never used} {row 1 missing from index i2}} do_test pragma-3.17 { execsql { PRAGMA integrity_check=8 @@ -412,7 +412,7 @@ Page 6 is never used} {rowid 1 missing from index i2}} } {{*** in database t2 *** Page 4 is never used Page 5 is never used -Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** Page 4 is never used Page 5 is never used}} do_test pragma-3.18 { @@ -422,7 +422,7 @@ Page 5 is never used}} } {{*** in database t2 *** Page 4 is never used Page 5 is never used -Page 6 is never used} {rowid 1 missing from index i2}} +Page 6 is never used} {row 1 missing from index i2}} } do_test pragma-3.19 { catch {db close} @@ -431,7 +431,32 @@ Page 6 is never used} {rowid 1 missing from index i2}} db eval {PRAGMA integrity_check} } {ok} } -#exit + +# Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL +# constraint violations. +# +do_execsql_test pragma-3.20 { + CREATE TABLE t1(a,b); + CREATE INDEX t1a ON t1(a); + INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(2,4),(NULL,5),(NULL,6); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE UNIQUE INDEX t1a ON t1(a)' + WHERE name='t1a'; + UPDATE sqlite_master SET sql='CREATE TABLE t1(a NOT NULL,b)' + WHERE name='t1'; + PRAGMA writable_schema=OFF; + ALTER TABLE t1 RENAME TO t1x; + PRAGMA integrity_check; +} {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a} {NULL value in t1x.a}} +do_execsql_test pragma-3.21 { + PRAGMA integrity_check(3); +} {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a}} +do_execsql_test pragma-3.22 { + PRAGMA integrity_check(2); +} {{non-unique entry in index t1a} {NULL value in t1x.a}} +do_execsql_test pragma-3.21 { + PRAGMA integrity_check(1); +} {{non-unique entry in index t1a}} # Test modifying the cache_size of an attached database. ifcapable pager_pragmas&&attach { @@ -1575,6 +1600,8 @@ do_test pragma-20.8 { forcedelete data_dir } ;# endif windows +database_may_be_corrupt + do_test 21.1 { # Create a corrupt database in testerr.db. And a non-corrupt at test.db. # @@ -1600,11 +1627,16 @@ Multiple uses for byte 672 of page 15} set auxerr {*** in database aux *** Multiple uses for byte 672 of page 15} +set mainerr {/{\*\*\* in database main \*\*\* +Multiple uses for byte 672 of page 15}.*/} +set auxerr {/{\*\*\* in database aux \*\*\* +Multiple uses for byte 672 of page 15}.*/} + do_test 22.2 { catch { db close } sqlite3 db testerr.db execsql { PRAGMA integrity_check } -} [list $mainerr] +} $mainerr do_test 22.3.1 { catch { db close } @@ -1613,13 +1645,13 @@ do_test 22.3.1 { ATTACH 'testerr.db' AS 'aux'; PRAGMA integrity_check; } -} [list $auxerr] +} $auxerr do_test 22.3.2 { execsql { PRAGMA main.integrity_check; } } {ok} do_test 22.3.3 { execsql { PRAGMA aux.integrity_check; } -} [list $auxerr] +} $auxerr do_test 22.4.1 { catch { db close } @@ -1628,10 +1660,10 @@ do_test 22.4.1 { ATTACH 'test.db' AS 'aux'; PRAGMA integrity_check; } -} [list $mainerr] +} $mainerr do_test 22.4.2 { execsql { PRAGMA main.integrity_check; } -} [list $mainerr] +} $mainerr do_test 22.4.3 { execsql { PRAGMA aux.integrity_check; } } {ok} @@ -1680,4 +1712,5 @@ do_test 23.5 { } } {0 0 t1 y {} {NO ACTION} {NO ACTION} NONE} +database_never_corrupt finish_test diff --git a/test/pragma2.test b/test/pragma2.test index 1111a98..0dbc977 100644 --- a/test/pragma2.test +++ b/test/pragma2.test @@ -22,6 +22,7 @@ source $testdir/tester.tcl # pragma2-1.*: Test freelist_count pragma on the main database. # pragma2-2.*: Test freelist_count pragma on an attached database. # pragma2-3.*: Test trying to write to the freelist_count is a no-op. +# pragma2-4.*: Tests for PRAGMA cache_spill # ifcapable !pragma||!schema_pragmas { @@ -116,4 +117,92 @@ ifcapable attach { } {9 9} } +# Default setting of PRAGMA cache_spill is always ON +# +# EVIDENCE-OF: R-51036-62828 PRAGMA cache_spill; PRAGMA +# cache_spill=boolean; +# +# EVIDENCE-OF: R-23955-02765 Cache_spill is enabled by default +# +db close +delete_file test.db test.db-journal +delete_file test2.db test2.db-journal +sqlite3 db test.db +do_execsql_test pragma2-4.1 { + PRAGMA cache_spill; + PRAGMA main.cache_spill; + PRAGMA temp.cache_spill; +} {1 1 1} +do_execsql_test pragma2-4.2 { + PRAGMA cache_spill=OFF; + PRAGMA cache_spill; + PRAGMA main.cache_spill; + PRAGMA temp.cache_spill; +} {0 0 0} +do_execsql_test pragma2-4.3 { + PRAGMA page_size=1024; + PRAGMA cache_size=50; + BEGIN; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d); + INSERT INTO t1 VALUES(1, randomblob(400), 1, randomblob(400)); + INSERT INTO t1 SELECT a+1, randomblob(400), a+1, randomblob(400) FROM t1; + INSERT INTO t1 SELECT a+2, randomblob(400), a+2, randomblob(400) FROM t1; + INSERT INTO t1 SELECT a+4, randomblob(400), a+4, randomblob(400) FROM t1; + INSERT INTO t1 SELECT a+8, randomblob(400), a+8, randomblob(400) FROM t1; + INSERT INTO t1 SELECT a+16, randomblob(400), a+16, randomblob(400) FROM t1; + INSERT INTO t1 SELECT a+32, randomblob(400), a+32, randomblob(400) FROM t1; + INSERT INTO t1 SELECT a+64, randomblob(400), a+64, randomblob(400) FROM t1; + COMMIT; + ATTACH 'test2.db' AS aux1; + CREATE TABLE aux1.t2(a INTEGER PRIMARY KEY, b, c, d); + INSERT INTO t2 SELECT * FROM t1; + DETACH aux1; + PRAGMA cache_spill=ON; +} {} +sqlite3_release_memory +# +# EVIDENCE-OF: R-07634-40532 The cache_spill pragma enables or disables +# the ability of the pager to spill dirty cache pages to the database +# file in the middle of a transaction. +# +do_test pragma2-4.4 { + db eval { + BEGIN; + UPDATE t1 SET c=c+1; + PRAGMA lock_status; + } +} {main exclusive temp unknown} ;# EXCLUSIVE lock due to cache spill +do_test pragma2-4.5 { + db eval { + COMMIT; + PRAGMA cache_spill=OFF; + BEGIN; + UPDATE t1 SET c=c-1; + PRAGMA lock_status; + } +} {main reserved temp unknown} ;# No cache spill, so no exclusive lock + +# Verify that newly attached databases inherit the cache_spill=OFF +# setting. +# +do_execsql_test pragma2-4.6 { + COMMIT; + ATTACH 'test2.db' AS aux1; + PRAGMA aux1.cache_size=50; + BEGIN; + UPDATE t2 SET c=c+1; + PRAGMA lock_status; +} {main unlocked temp unknown aux1 reserved} +do_execsql_test pragma2-4.7 { + COMMIT; +} +sqlite3_release_memory +do_execsql_test pragma2-4.8 { + PRAGMA cache_spill=ON; -- Applies to all databases + BEGIN; + UPDATE t2 SET c=c-1; + PRAGMA lock_status; +} {main unlocked temp unknown aux1 exclusive} + + finish_test diff --git a/test/printf2.test b/test/printf2.test new file mode 100644 index 0000000..4cb1783 --- /dev/null +++ b/test/printf2.test @@ -0,0 +1,99 @@ +# 2013-12-17 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the printf() SQL function. +# +# +# EVIDENCE-OF: R-63057-40065 The printf(FORMAT,...) SQL function works +# like the sqlite3_mprintf() C-language function and the printf() +# function from the standard C library. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# EVIDENCE-OF: R-40086-60101 If the FORMAT argument is missing or NULL +# then the result is NULL. +# +do_execsql_test printf2-1.1 { + SELECT quote(printf()), quote(printf(NULL,1,2,3)); +} {NULL NULL} + + +do_execsql_test printf2-1.2 { + SELECT printf('hello'); +} {hello} +do_execsql_test printf2-1.3 { + SELECT printf('%d,%d,%d',55,-11,3421); +} {55,-11,3421} +do_execsql_test printf2-1.4 { + SELECT printf('%d,%d,%d',55,'-11',3421); +} {55,-11,3421} +do_execsql_test printf2-1.5 { + SELECT printf('%d,%d,%d,%d',55,'-11',3421); +} {55,-11,3421,0} +do_execsql_test printf2-1.6 { + SELECT printf('%.2f',3.141592653); +} {3.14} +do_execsql_test printf2-1.7 { + SELECT printf('%.*f',2,3.141592653); +} {3.14} +do_execsql_test printf2-1.8 { + SELECT printf('%*.*f',5,2,3.141592653); +} {{ 3.14}} +do_execsql_test printf2-1.9 { + SELECT printf('%d',314159.2653); +} {314159} +do_execsql_test printf2-1.10 { + SELECT printf('%lld',314159.2653); +} {314159} +do_execsql_test printf2-1.11 { + SELECT printf('%lld%n',314159.2653,'hi'); +} {314159} + +# EVIDENCE-OF: R-17002-27534 The %z format is interchangeable with %s. +# +do_execsql_test printf2-1.12 { + SELECT printf('%.*z',5,'abcdefghijklmnop'); +} {abcde} +do_execsql_test printf2-1.13 { + SELECT printf('%c','abcdefghijklmnop'); +} {a} + +# EVIDENCE-OF: R-02347-27622 The %n format is silently ignored and does +# not consume an argument. +# +do_execsql_test printf2-2.1 { + CREATE TABLE t1(a,b,c); + INSERT INTO t1 VALUES(1,2,3); + INSERT INTO t1 VALUES(-1,-2,-3); + INSERT INTO t1 VALUES('abc','def','ghi'); + INSERT INTO t1 VALUES(1.5,2.25,3.125); + SELECT printf('(%s)-%n-(%s)',a,b,c) FROM t1 ORDER BY rowid; +} {(1)--(2) (-1)--(-2) (abc)--(def) (1.5)--(2.25)} + +# EVIDENCE-OF: R-56064-04001 The %p format is an alias for %X. +# +do_execsql_test printf2-2.2 { + SELECT printf('%s=(%p)',a,a) FROM t1 ORDER BY a; +} {-1=(FFFFFFFFFFFFFFFF) 1=(1) 1.5=(1) abc=(0)} + +# EVIDENCE-OF: R-29410-53018 If there are too few arguments in the +# argument list, missing arguments are assumed to have a NULL value, +# which is translated into 0 or 0.0 for numeric formats or an empty +# string for %s. +# +do_execsql_test printf2-2.3 { + SELECT printf('%s=(%d/%g/%s)',a) FROM t1 ORDER BY a; +} {-1=(0/0/) 1=(0/0/) 1.5=(0/0/) abc=(0/0/)} + + +finish_test diff --git a/test/progress.test b/test/progress.test index b25a100..993426a 100644 --- a/test/progress.test +++ b/test/progress.test @@ -164,10 +164,12 @@ do_test progress-1.7 { } set ::res [list] + explain {SELECT a, b, c FROM abc} db eval {SELECT a, b, c FROM abc} { lappend ::res $a $b $c - db progress 10 "expr 1" + db progress 5 "expr 1" catch {db eval {SELECT a, b, c FROM abc} { }} msg + db progress 5 "expr 0" lappend ::res $msg } diff --git a/test/queryonly.test b/test/queryonly.test new file mode 100644 index 0000000..2774e5d --- /dev/null +++ b/test/queryonly.test @@ -0,0 +1,72 @@ +# 2013-07-11 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file tests the "query_only" pragma. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test queryonly-1.1 { + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(123),(456); + SELECT a FROM t1 ORDER BY a; +} {123 456} +do_execsql_test queryonly-1.2 { + PRAGMA query_only; +} {0} +do_execsql_test queryonly-1.3 { + PRAGMA query_only=ON; + PRAGMA query_only; +} {1} +do_test queryonly-1.4 { + catchsql {INSERT INTO t1 VALUES(789);} +} {1 {attempt to write a readonly database}} +do_test queryonly-1.5 { + catchsql {DELETE FROM t1;} +} {1 {attempt to write a readonly database}} +do_test queryonly-1.6 { + catchsql {UPDATE t1 SET a=a+1;} +} {1 {attempt to write a readonly database}} +do_test queryonly-1.7 { + catchsql {CREATE TABLE t2(b);} +} {1 {attempt to write a readonly database}} +do_test queryonly-1.8 { + catchsql {CREATE INDEX t1a ON t1(a);} +} {1 {attempt to write a readonly database}} +do_test queryonly-1.9 { + catchsql {DROP TABLE t1;} +} {1 {attempt to write a readonly database}} +do_test queryonly-1.10 { + catchsql {ANALYZE;} +} {1 {attempt to write a readonly database}} +do_execsql_test queryonly-1.11 { + SELECT a FROM t1 ORDER BY a; +} {123 456} + +do_execsql_test queryonly-2.2 { + PRAGMA query_only; +} {1} +do_execsql_test queryonly-2.3 { + PRAGMA query_only=OFF; + PRAGMA query_only; +} {0} +do_execsql_test queryonly-2.4 { + INSERT INTO t1 VALUES(789); + SELECT a FROM t1 ORDER BY a; +} {123 456 789} +do_execsql_test queryonly-2.5 { + UPDATE t1 SET a=a+1; + SELECT a FROM t1 ORDER BY a; +} {124 457 790} + +finish_test diff --git a/test/quota.test b/test/quota.test index 816dec8..f9655fb 100644 --- a/test/quota.test +++ b/test/quota.test @@ -361,7 +361,7 @@ foreach file [glob -nocomplain quota-test-A*] { do_test quota-4.4.1 { set ::quota {} sqlite3_quota_set $::quotagroup 10000 quota_callback - file delete -force ./quota-test-A1.db ./quota-test-A2.db + forcedelete ./quota-test-A1.db ./quota-test-A2.db sqlite3 db ./quota-test-A1.db db eval { CREATE TABLE t1(x); diff --git a/test/quota2.test b/test/quota2.test index 1482db6..8682bd8 100644 --- a/test/quota2.test +++ b/test/quota2.test @@ -25,7 +25,7 @@ db close sqlite3_quota_initialize "" 1 foreach dir {quota2a/x1 quota2a/x2 quota2a quota2b quota2c} { - file delete -force $dir + forcedelete $dir } foreach dir {quota2a quota2a/x1 quota2a/x2 quota2b quota2c} { file mkdir $dir diff --git a/test/rdonly.test b/test/rdonly.test index bf19597..938cc78 100644 --- a/test/rdonly.test +++ b/test/rdonly.test @@ -32,6 +32,9 @@ do_test rdonly-1.1 { SELECT * FROM t1; } } {1} +do_test rdonly-1.1.1 { + sqlite3_db_readonly db main +} {0} # Changes the write version from 1 to 3. Verify that the database # can be read but not written. @@ -47,6 +50,9 @@ do_test rdonly-1.3 { SELECT * FROM t1; } } {1} +do_test rdonly-1.3.1 { + sqlite3_db_readonly db main +} {1} do_test rdonly-1.4 { catchsql { INSERT INTO t1 VALUES(2) diff --git a/test/releasetest.tcl b/test/releasetest.tcl index b635061..eb2e440 100644 --- a/test/releasetest.tcl +++ b/test/releasetest.tcl @@ -176,6 +176,12 @@ array set ::Configs { -DSQLITE_DISABLE_FTS4_DEFERRED -DSQLITE_ENABLE_RTREE } + + "No-lookaside" { + -DSQLITE_TEST_REALLOC_STRESS=1 + -DSQLITE_OMIT_LOOKASIDE=1 + -DHAVE_USLEEP=1 + } } array set ::Platforms { @@ -188,6 +194,7 @@ array set ::Platforms { "Extra-Robustness" test "Device-Two" test "Ftrapv" test + "No-lookaside" test "Default" "threadtest test" "Device-One" fulltest } diff --git a/test/resolver01.test b/test/resolver01.test index 3ca6ace..7d95a21 100644 --- a/test/resolver01.test +++ b/test/resolver01.test @@ -13,10 +13,18 @@ # figures out what identifiers in the SQL statement refer to) that # were fixed by ticket [2500cdb9be] # +# See also tickets [1c69be2daf] and [f617ea3125] from 2013-08-14. +# set testdir [file dirname $argv0] source $testdir/tester.tcl +# "ORDER BY y" binds to the output result-set column named "y" +# if available. If no output column is named "y", then try to +# bind against an input column named "y". +# +# This is classical SQL92 behavior. +# do_test resolver01-1.1 { catchsql { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(11,22); @@ -26,14 +34,175 @@ do_test resolver01-1.1 { } {0 1} do_test resolver01-1.2 { catchsql { + SELECT 1 AS yy FROM t1, t2 ORDER BY y; + } +} {1 {ambiguous column name: y}} +do_test resolver01-1.3 { + catchsql { + CREATE TABLE t3(x,y); INSERT INTO t3 VALUES(11,44),(33,22); + SELECT x AS y FROM t3 ORDER BY y; + } +} {0 {11 33}} +do_test resolver01-1.4 { + catchsql { + SELECT x AS yy FROM t3 ORDER BY y; + } +} {0 {33 11}} + +# SQLite allows the WHERE clause to reference output columns if there is +# no other way to resolve the name. +# +do_test resolver01-1.5 { + catchsql { + SELECT x AS yy FROM t3 ORDER BY yy; + } +} {0 {11 33}} +do_test resolver01-1.6 { + catchsql { + SELECT x AS yy FROM t3 ORDER BY 1; + } +} {0 {11 33}} + +# The "ORDER BY y COLLATE nocase" form works the same as "ORDER BY y". +# The "y" binds more tightly to output columns than to input columns. +# +# This is for compatibility with SQL92 and with historical SQLite behavior. +# Note that PostgreSQL considers "y COLLATE nocase" to be an expression +# and thus PostgreSQL treats this case as if it where the 3.x case below. +# +do_test resolver01-2.1 { + catchsql { SELECT 2 AS y FROM t1, t2 ORDER BY y COLLATE nocase; } } {0 2} -do_test resolver01-1.3 { +do_test resolver01-2.2 { + catchsql { + SELECT 2 AS yy FROM t1, t2 ORDER BY y COLLATE nocase; + } +} {1 {ambiguous column name: y}} +do_test resolver01-2.3 { + catchsql { + SELECT x AS y FROM t3 ORDER BY y COLLATE nocase; + } +} {0 {11 33}} +do_test resolver01-2.4 { + catchsql { + SELECT x AS yy FROM t3 ORDER BY y COLLATE nocase; + } +} {0 {33 11}} +do_test resolver01-2.5 { + catchsql { + SELECT x AS yy FROM t3 ORDER BY yy COLLATE nocase; + } +} {0 {11 33}} +do_test resolver01-2.6 { + catchsql { + SELECT x AS yy FROM t3 ORDER BY 1 COLLATE nocase; + } +} {0 {11 33}} + +# But if the form is "ORDER BY expr" then bind more tightly to the +# the input column names and only use the output column names if no +# input column name matches. +# +# This is SQL99 behavior, as implemented by PostgreSQL and MS-SQL. +# Note that Oracle works differently. +# +do_test resolver01-3.1 { catchsql { SELECT 3 AS y FROM t1, t2 ORDER BY +y; } -} {0 3} +} {1 {ambiguous column name: y}} +do_test resolver01-3.2 { + catchsql { + SELECT 2 AS yy FROM t1, t2 ORDER BY +y; + } +} {1 {ambiguous column name: y}} +do_test resolver01-3.3 { + catchsql { + SELECT x AS y FROM t3 ORDER BY +y; + } +} {0 {33 11}} +do_test resolver01-3.4 { + catchsql { + SELECT x AS yy FROM t3 ORDER BY +y; + } +} {0 {33 11}} +do_test resolver01-3.5 { + catchsql { + SELECT x AS yy FROM t3 ORDER BY +yy + } +} {0 {11 33}} + +# This is the test case given in ticket [f617ea3125e9] (with table name +# changed from "t1" to "t4". The behavior of (1) and (3) match with +# PostgreSQL, but we intentionally break with PostgreSQL to provide +# SQL92 behavior for case (2). +# +do_execsql_test resolver01-4.1 { + CREATE TABLE t4(m CHAR(2)); + INSERT INTO t4 VALUES('az'); + INSERT INTO t4 VALUES('by'); + INSERT INTO t4 VALUES('cx'); + SELECT '1', substr(m,2) AS m FROM t4 ORDER BY m; + SELECT '2', substr(m,2) AS m FROM t4 ORDER BY m COLLATE binary; + SELECT '3', substr(m,2) AS m FROM t4 ORDER BY lower(m); +} {1 x 1 y 1 z 2 x 2 y 2 z 3 z 3 y 3 x} + +########################################################################## +# Test cases for ticket [1c69be2dafc28]: Make sure the GROUP BY binds +# more tightly to the input tables in all cases. +# +# This first case case has been wrong in SQLite for time out of mind. +# For SQLite version 3.7.17 the answer was two rows, which is wrong. +# +do_execsql_test resolver01-5.1 { + CREATE TABLE t5(m CHAR(2)); + INSERT INTO t5 VALUES('ax'); + INSERT INTO t5 VALUES('bx'); + INSERT INTO t5 VALUES('cy'); + SELECT count(*), substr(m,2,1) AS m FROM t5 GROUP BY m ORDER BY 1, 2; +} {1 x 1 x 1 y} + +# This case is unambiguous and has always been correct. +# +do_execsql_test resolver01-5.2 { + SELECT count(*), substr(m,2,1) AS mx FROM t5 GROUP BY m ORDER BY 1, 2; +} {1 x 1 x 1 y} + +# This case is not allowed in standard SQL, but SQLite allows and does +# the sensible thing. +# +do_execsql_test resolver01-5.3 { + SELECT count(*), substr(m,2,1) AS mx FROM t5 GROUP BY mx ORDER BY 1, 2; +} {1 y 2 x} +do_execsql_test resolver01-5.4 { + SELECT count(*), substr(m,2,1) AS mx FROM t5 + GROUP BY substr(m,2,1) ORDER BY 1, 2; +} {1 y 2 x} + +# These test case weere provided in the 2013-08-14 email from Rob Golsteijn +# that originally reported the problem of ticket [1c69be2dafc28]. +# +do_execsql_test resolver01-6.1 { + CREATE TABLE t61(name); + SELECT min(name) FROM t61 GROUP BY lower(name); +} {} +do_execsql_test resolver01-6.2 { + SELECT min(name) AS name FROM t61 GROUP BY lower(name); +} {} +do_execsql_test resolver01-6.3 { + CREATE TABLE t63(name); + INSERT INTO t63 VALUES (NULL); + INSERT INTO t63 VALUES ('abc'); + SELECT count(), + NULLIF(name,'abc') AS name + FROM t63 + GROUP BY lower(name); +} {1 {} 1 {}} + + + finish_test diff --git a/test/rollback.test b/test/rollback.test index fc123ab..c339c5d 100644 --- a/test/rollback.test +++ b/test/rollback.test @@ -54,7 +54,7 @@ ifcapable conflict { catchsql { INSERT INTO t3 SELECT a FROM t1; } - } {1 {column a is not unique}} + } {1 {UNIQUE constraint failed: t3.a}} # Try to continue with the SELECT statement # diff --git a/test/rowid.test b/test/rowid.test index 5daf581..6d068d7 100644 --- a/test/rowid.test +++ b/test/rowid.test @@ -12,7 +12,9 @@ # focus of this file is testing the magic ROWID column that is # found on all tables. # -# $Id: rowid.test,v 1.21 2009/06/26 15:14:55 drh Exp $ +# EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a +# special column, usually called the "rowid", that uniquely identifies +# that row within the table. set testdir [file dirname $argv0] source $testdir/tester.tcl diff --git a/test/run-wordcount.sh b/test/run-wordcount.sh new file mode 100644 index 0000000..1755d58 --- /dev/null +++ b/test/run-wordcount.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# This script runs the wordcount program in different ways, comparing +# the output from each. +# + +# Select the source text to be analyzed. +# +if test "x$1" = "x"; +then echo "Usage: $0 FILENAME [ARGS...]"; exit 1; +fi + +# Do test runs +# +rm -f wcdb1.db +./wordcount --timer --summary wcdb1.db $* --insert >wc-out.txt +mv wc-out.txt wc-baseline.txt +rm -f wcdb2.db +./wordcount --timer --summary wcdb2.db $* --insert --without-rowid >wc-out.txt + if cmp -s wc-out.txt wc-baseline.txt; + then echo hi >/dev/null; + else echo ERROR:; + diff -u wc-baseline.txt wc-out.txt; + fi + +rm -f wcdb1.db +./wordcount --timer --summary wcdb1.db $* --replace >wc-out.txt + if cmp -s wc-out.txt wc-baseline.txt; + then echo hi >/dev/null; + else echo ERROR:; + diff -u wc-baseline.txt wc-out.txt; + fi +rm -f wcdb2.db +./wordcount --timer --summary wcdb2.db $* --replace --without-rowid >wc-out.txt + if cmp -s wc-out.txt wc-baseline.txt; + then echo hi >/dev/null; + else echo ERROR:; + diff -u wc-baseline.txt wc-out.txt; + fi + +rm -f wcdb1.db +./wordcount --timer --summary wcdb1.db $* --select >wc-out.txt + if cmp -s wc-out.txt wc-baseline.txt; + then echo hi >/dev/null; + else echo ERROR:; + diff -u wc-baseline.txt wc-out.txt; + fi + +rm -f wcdb2.db +./wordcount --timer --summary wcdb2.db $* --select --without-rowid >wc-out.txt + if cmp -s wc-out.txt wc-baseline.txt; + then echo hi >/dev/null; + else echo ERROR:; + diff -u wc-baseline.txt wc-out.txt; + fi + +./wordcount --timer --summary wcdb1.db $* --query >wc-out.txt +mv wc-out.txt wc-baseline.txt +./wordcount --timer --summary wcdb2.db $* --query --without-rowid >wc-out.txt + if cmp -s wc-out.txt wc-baseline.txt; + then echo hi >/dev/null; + else echo ERROR:; + diff -u wc-baseline.txt wc-out.txt; + fi + +./wordcount --timer --summary wcdb1.db $* --delete >wc-out.txt +mv wc-out.txt wc-baseline.txt +./wordcount --timer --summary wcdb2.db $* --delete --without-rowid >wc-out.txt + if cmp -s wc-out.txt wc-baseline.txt; + then echo hi >/dev/null; + else echo ERROR:; + diff -u wc-baseline.txt wc-out.txt; + fi + + +# Clean up temporary files created. +# +rm -rf wcdb1.db wcdb2.db wc-out.txt wc-baseline.txt diff --git a/test/savepoint.test b/test/savepoint.test index 015d97f..9f4571a 100644 --- a/test/savepoint.test +++ b/test/savepoint.test @@ -858,7 +858,7 @@ do_test savepoint-12.2 { SAVEPOINT sp2; INSERT OR ROLLBACK INTO t4 VALUES(1, 'one'); } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: t4.a}} do_test savepoint-12.3 { sqlite3_get_autocommit db } {1} diff --git a/test/schema5.test b/test/schema5.test index 6dea5e8..29df3f1 100644 --- a/test/schema5.test +++ b/test/schema5.test @@ -30,7 +30,7 @@ do_test schema5-1.1 { } {1 2 3} do_test schema5-1.2 { catchsql {INSERT INTO t1 VALUES(1,3,4);} -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test schema5-1.3 { db eval { DROP TABLE t1; @@ -44,7 +44,7 @@ do_test schema5-1.3 { } {1 2 3} do_test schema5-1.4 { catchsql {INSERT INTO t1 VALUES(10,11,12);} -} {1 {constraint two failed}} +} {1 {CHECK constraint failed: two}} do_test schema5-1.5 { db eval { DROP TABLE t1; @@ -57,10 +57,10 @@ do_test schema5-1.5 { } {} do_test schema5-1.6 { catchsql {INSERT INTO t1 VALUES(1,3,4)} -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test schema5-1.7 { catchsql {INSERT INTO t1 VALUES(10,2,3)} -} {1 {columns b, c are not unique}} +} {1 {UNIQUE constraint failed: t1.b, t1.c}} diff --git a/test/securedel.test b/test/securedel.test index 7ff5a62..7111e08 100644 --- a/test/securedel.test +++ b/test/securedel.test @@ -47,7 +47,6 @@ do_test securedel-1.3 { } } {0 0} do_test securedel-1.4 { -breakpoint db eval { PRAGMA secure_delete=ON; PRAGMA db2.secure_delete; diff --git a/test/securedel2.test b/test/securedel2.test index b20f4f9..9badc56 100644 --- a/test/securedel2.test +++ b/test/securedel2.test @@ -92,4 +92,3 @@ do_test 1.6.2 { } {0} finish_test - diff --git a/test/select1.test b/test/select1.test index 852b52e..875c87c 100644 --- a/test/select1.test +++ b/test/select1.test @@ -542,7 +542,7 @@ do_test select1-6.9.7 { set x [execsql2 { SELECT * FROM test1 a, (select 5, 6) LIMIT 1 }] - regsub -all {subquery_[0-9a-fA-F]+_} $x {subquery} x + regsub -all {sq_[0-9a-fA-F_]+} $x {subquery} x set x } {a.f1 11 a.f2 22 sqlite_subquery.5 5 sqlite_subquery.6 6} do_test select1-6.9.8 { diff --git a/test/select4.test b/test/select4.test index e205b37..8fc200d 100644 --- a/test/select4.test +++ b/test/select4.test @@ -824,4 +824,40 @@ do_test select4-13.1 { } } {1 2} +# 2014-02-18: Make sure compound SELECTs work with VALUES clauses +# +do_execsql_test select4-14.1 { + CREATE TABLE t14(a,b,c); + INSERT INTO t14 VALUES(1,2,3),(4,5,6); + SELECT * FROM t14 INTERSECT VALUES(3,2,1),(2,3,1),(1,2,3),(2,1,3); +} {1 2 3} +do_execsql_test select4-14.2 { + SELECT * FROM t14 INTERSECT VALUES(1,2,3); +} {1 2 3} +do_execsql_test select4-14.3 { + SELECT * FROM t14 + UNION VALUES(3,2,1),(2,3,1),(1,2,3),(7,8,9),(4,5,6) + UNION SELECT * FROM t14 ORDER BY 1, 2, 3 +} {1 2 3 2 3 1 3 2 1 4 5 6 7 8 9} +do_execsql_test select4-14.4 { + SELECT * FROM t14 + UNION VALUES(3,2,1) + UNION SELECT * FROM t14 ORDER BY 1, 2, 3 +} {1 2 3 3 2 1 4 5 6} +do_execsql_test select4-14.5 { + SELECT * FROM t14 EXCEPT VALUES(3,2,1),(2,3,1),(1,2,3),(2,1,3); +} {4 5 6} +do_execsql_test select4-14.6 { + SELECT * FROM t14 EXCEPT VALUES(1,2,3) +} {4 5 6} +do_execsql_test select4-14.7 { + SELECT * FROM t14 EXCEPT VALUES(1,2,3) EXCEPT VALUES(4,5,6) +} {} +do_execsql_test select4-14.8 { + SELECT * FROM t14 EXCEPT VALUES('a','b','c') EXCEPT VALUES(4,5,6) +} {1 2 3} +do_execsql_test select4-14.9 { + SELECT * FROM t14 UNION ALL VALUES(3,2,1),(2,3,1),(1,2,3),(2,1,3); +} {1 2 3 4 5 6 3 2 1 2 3 1 1 2 3 2 1 3} + finish_test diff --git a/test/select7.test b/test/select7.test index e8fc440..6816b9f 100644 --- a/test/select7.test +++ b/test/select7.test @@ -138,21 +138,23 @@ ifcapable {subquery && compound} { # Verify that an error occurs if you have too many terms on a # compound select statement. # -ifcapable compound { - if {$SQLITE_MAX_COMPOUND_SELECT>0} { - set sql {SELECT 0} - set result 0 - for {set i 1} {$i<$SQLITE_MAX_COMPOUND_SELECT} {incr i} { - append sql " UNION ALL SELECT $i" - lappend result $i +if {[clang_sanitize_address]==0} { + ifcapable compound { + if {$SQLITE_MAX_COMPOUND_SELECT>0} { + set sql {SELECT 0} + set result 0 + for {set i 1} {$i<$SQLITE_MAX_COMPOUND_SELECT} {incr i} { + append sql " UNION ALL SELECT $i" + lappend result $i + } + do_test select7-6.1 { + catchsql $sql + } [list 0 $result] + append sql { UNION ALL SELECT 99999999} + do_test select7-6.2 { + catchsql $sql + } {1 {too many terms in compound SELECT}} } - do_test select7-6.1 { - catchsql $sql - } [list 0 $result] - append sql { UNION ALL SELECT 99999999} - do_test select7-6.2 { - catchsql $sql - } {1 {too many terms in compound SELECT}} } } diff --git a/test/select9.test b/test/select9.test index 9f54014..4c42236 100644 --- a/test/select9.test +++ b/test/select9.test @@ -450,5 +450,23 @@ do_test select9-5.3 { } } {/SCAN TABLE/} ;# Full table scan if the "+x" prevents index usage. +# 2013-07-09: Ticket [490a4b7235624298]: +# "WHERE 0" on the first element of a UNION causes an assertion fault +# +do_execsql_test select9-6.1 { + CREATE TABLE t61(a); + CREATE TABLE t62(b); + INSERT INTO t61 VALUES(111); + INSERT INTO t62 VALUES(222); + SELECT a FROM t61 WHERE 0 UNION SELECT b FROM t62; +} {222} +do_execsql_test select9-6.2 { + SELECT a FROM t61 WHERE 0 UNION ALL SELECT b FROM t62; +} {222} +do_execsql_test select9-6.3 { + SELECT a FROM t61 UNION SELECT b FROM t62 WHERE 0; +} {111} + + finish_test diff --git a/test/selectA.test b/test/selectA.test index 5fd2288..6e593e8 100644 --- a/test/selectA.test +++ b/test/selectA.test @@ -21,6 +21,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix selectA ifcapable !compound { finish_test @@ -1292,5 +1293,86 @@ do_test selectA-3.97 { ORDER BY y COLLATE NOCASE DESC,x,z))) } } {MAD} +do_execsql_test selectA-3.98 { + WITH RECURSIVE + xyz(n) AS ( + SELECT upper((SELECT x FROM ( + SELECT x,y,z FROM t2 + INTERSECT SELECT a,b,c FROM t3 + EXCEPT SELECT c,b,a FROM t1 + UNION SELECT a,b,c FROM t3 + INTERSECT SELECT a,b,c FROM t3 + EXCEPT SELECT c,b,a FROM t1 + UNION SELECT a,b,c FROM t3 + ORDER BY y COLLATE NOCASE DESC,x,z))) + UNION ALL + SELECT n || '+' FROM xyz WHERE length(n)<5 + ) + SELECT n FROM xyz ORDER BY +n; +} {MAD MAD+ MAD++} + +#------------------------------------------------------------------------- +# At one point the following code exposed a temp register reuse problem. +# +proc f {args} { return 1 } +db func f f + +do_execsql_test 4.1.1 { + CREATE TABLE t4(a, b); + CREATE TABLE t5(c, d); + + INSERT INTO t5 VALUES(1, 'x'); + INSERT INTO t5 VALUES(2, 'x'); + INSERT INTO t4 VALUES(3, 'x'); + INSERT INTO t4 VALUES(4, 'x'); + + CREATE INDEX i1 ON t4(a); + CREATE INDEX i2 ON t5(c); +} + +do_eqp_test 4.1.2 { + SELECT c, d FROM t5 + UNION ALL + SELECT a, b FROM t4 WHERE f()==f() + ORDER BY 1,2 +} { + 1 0 0 {SCAN TABLE t5 USING INDEX i2} + 1 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} + 2 0 0 {SCAN TABLE t4 USING INDEX i1} + 2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} + 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} +} + +do_execsql_test 4.1.3 { + SELECT c, d FROM t5 + UNION ALL + SELECT a, b FROM t4 WHERE f()==f() + ORDER BY 1,2 +} { + 1 x 2 x 3 x 4 x +} + +do_execsql_test 4.2.1 { + CREATE TABLE t6(a, b); + CREATE TABLE t7(c, d); + + INSERT INTO t7 VALUES(2, 9); + INSERT INTO t6 VALUES(3, 0); + INSERT INTO t6 VALUES(4, 1); + INSERT INTO t7 VALUES(5, 6); + INSERT INTO t6 VALUES(6, 0); + INSERT INTO t7 VALUES(7, 6); + + CREATE INDEX i6 ON t6(a); + CREATE INDEX i7 ON t7(c); +} + +do_execsql_test 4.2.2 { + SELECT c, f(d,c,d,c,d) FROM t7 + UNION ALL + SELECT a, b FROM t6 + ORDER BY 1,2 +} {/2 . 3 . 4 . 5 . 6 . 7 ./} + finish_test diff --git a/test/selectF.test b/test/selectF.test new file mode 100644 index 0000000..3fb226e --- /dev/null +++ b/test/selectF.test @@ -0,0 +1,49 @@ +# 2014-03-03 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file verifies that an OP_Copy operation is used instead of OP_SCopy +# in a compound select in a case where the source register might be changed +# before the copy is used. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix selectF + +do_execsql_test 1 { + BEGIN TRANSACTION; + CREATE TABLE t1(a, b, c); + INSERT INTO "t1" VALUES(1,'one','I'); + CREATE TABLE t2(d, e, f); + INSERT INTO "t2" VALUES(5,'ten','XX'); + INSERT INTO "t2" VALUES(6,NULL,NULL); + + CREATE INDEX i1 ON t1(b, a); + COMMIT; +} + +#explain_i { +# SELECT * FROM t2 +# UNION ALL +# SELECT * FROM t1 WHERE a<5 +# ORDER BY 2, 1 +#} + +do_execsql_test 2 { + SELECT * FROM t2 + UNION ALL + SELECT * FROM t1 WHERE a<5 + ORDER BY 2, 1 +} {6 {} {} 1 one I 5 ten XX} + + + +finish_test diff --git a/test/shared3.test b/test/shared3.test index 783ae6a..acc86d2 100644 --- a/test/shared3.test +++ b/test/shared3.test @@ -13,6 +13,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix shared3 db close ifcapable !shared_cache { @@ -103,5 +104,39 @@ db1 close db2 close db3 close +#------------------------------------------------------------------------- +# At one point this was causing a faulty assert to fail. +# +forcedelete test.db +sqlite3 db test.db +sqlite3 db2 test.db +do_execsql_test 3.1 { + PRAGMA auto_vacuum = 2; + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(randomblob(500), randomblob(500)); + INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; + INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; + INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; + INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; + INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; + INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; + INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; +} +do_test 3.2 { + execsql { SELECT count(*) FROM sqlite_master } db2 +} {1} +do_execsql_test 3.3 { + BEGIN; + DELETE FROM t1 WHERE 1; + PRAGMA incremental_vacuum; +} {} +do_test 3.4 { + execsql { SELECT count(*) FROM sqlite_master } db2 +} {1} +do_test 3.5 { + execsql { COMMIT } +} {} + sqlite3_enable_shared_cache $::enable_shared_cache finish_test + diff --git a/test/shared7.test b/test/shared7.test index 5c4a1da..9f4880f 100644 --- a/test/shared7.test +++ b/test/shared7.test @@ -23,6 +23,9 @@ do_test shared7-1.1 { sqlite3_enable_shared_cache } {1} +# EVIDENCE-OF: R-05098-06501 In shared cache mode, attempting to attach +# the same database file more than once results in an error. +# do_test shared7-1.2 { db close sqlite3 db test.db diff --git a/test/shared8.test b/test/shared8.test index 600e02b..73f0d47 100644 --- a/test/shared8.test +++ b/test/shared8.test @@ -110,4 +110,3 @@ do_test 1.8 { foreach db {db1 db2 db3 db4} { catch { $db close } } sqlite3_enable_shared_cache $::enable_shared_cache finish_test - diff --git a/test/sharedlock.test b/test/sharedlock.test index 1e78eea..caa48f5 100644 --- a/test/sharedlock.test +++ b/test/sharedlock.test @@ -13,6 +13,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix sharedlock db close ifcapable !shared_cache { @@ -47,9 +48,35 @@ do_test sharedlock-1.2 { set res } {1 one 2 two 3 three} + +#------------------------------------------------------------------------- +# Test that a write-lock is taken on a table when its entire contents +# are deleted using the OP_Clear optimization. +# +foreach {tn delete_sql} { + 1 { DELETE FROM t2 WHERE 1 } + 2 { DELETE FROM t2 } +} { + do_execsql_test 2.1 { + DROP TABLE IF EXISTS t2; + CREATE TABLE t2(x, y); + INSERT INTO t2 VALUES(1, 2); + INSERT INTO t2 VALUES(3, 4); + } + + do_test 2.2 { execsql { SELECT * FROM t2 } db2 } {1 2 3 4} + + do_execsql_test 2.3 " BEGIN; $delete_sql; " + + do_test 2.4 { + catchsql { SELECT * FROM t2 } db2 + } {1 {database table is locked: t2}} + + do_execsql_test 2.5 COMMIT +} + + db close db2 close - sqlite3_enable_shared_cache $::enable_shared_cache finish_test - diff --git a/test/shell1.test b/test/shell1.test index c60f3af..ab382e7 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -105,7 +105,7 @@ do_test shell1-1.7.1 { set rc [lindex $res 0] list $rc \ [regexp {SQLite version} $res] \ - [regexp {Enter SQL statements} $res] + [regexp {Enter ".help" for usage hints} $res] } {0 1 1} # -batch force batch I/O @@ -268,7 +268,7 @@ do_test shell1-3.1.4 { # .bail ON|OFF Stop after hitting an error. Default OFF do_test shell1-3.2.1 { catchcmd "test.db" ".bail" -} {1 {Error: unknown command or invalid arguments: "bail". Enter ".help" for help}} +} {1 {Usage: .bail on|off}} do_test shell1-3.2.2 { catchcmd "test.db" ".bail ON" } {0 {}} @@ -278,16 +278,16 @@ do_test shell1-3.2.3 { do_test shell1-3.2.4 { # too many arguments catchcmd "test.db" ".bail OFF BAD" -} {1 {Error: unknown command or invalid arguments: "bail". Enter ".help" for help}} +} {1 {Usage: .bail on|off}} # .databases List names and files of attached databases do_test shell1-3.3.1 { catchcmd "-csv test.db" ".databases" } "/0 +.*main +[string map {/ .} [string range [get_pwd] 0 10]].*/" do_test shell1-3.3.2 { - # too many arguments + # extra arguments ignored catchcmd "test.db" ".databases BAD" -} {1 {Error: unknown command or invalid arguments: "databases". Enter ".help" for help}} +} "/0 +.*main +[string map {/ .} [string range [get_pwd] 0 10]].*/" # .dump ?TABLE? ... Dump the database in an SQL text format # If TABLE specified, only dump tables matching @@ -305,12 +305,12 @@ do_test shell1-3.4.2 { do_test shell1-3.4.3 { # too many arguments catchcmd "test.db" ".dump FOO BAD" -} {1 {Error: unknown command or invalid arguments: "dump". Enter ".help" for help}} +} {1 {Usage: .dump ?LIKE-PATTERN?}} # .echo ON|OFF Turn command echo on or off do_test shell1-3.5.1 { catchcmd "test.db" ".echo" -} {1 {Error: unknown command or invalid arguments: "echo". Enter ".help" for help}} +} {1 {Usage: .echo on|off}} do_test shell1-3.5.2 { catchcmd "test.db" ".echo ON" } {0 {}} @@ -320,7 +320,7 @@ do_test shell1-3.5.3 { do_test shell1-3.5.4 { # too many arguments catchcmd "test.db" ".echo OFF BAD" -} {1 {Error: unknown command or invalid arguments: "echo". Enter ".help" for help}} +} {1 {Usage: .echo on|off}} # .exit Exit this program do_test shell1-3.6.1 { @@ -339,15 +339,15 @@ do_test shell1-3.7.3 { catchcmd "test.db" ".explain OFF" } {0 {}} do_test shell1-3.7.4 { - # too many arguments + # extra arguments ignored catchcmd "test.db" ".explain OFF BAD" -} {1 {Error: unknown command or invalid arguments: "explain". Enter ".help" for help}} +} {0 {}} # .header(s) ON|OFF Turn display of headers on or off do_test shell1-3.9.1 { catchcmd "test.db" ".header" -} {1 {Error: unknown command or invalid arguments: "header". Enter ".help" for help}} +} {1 {Usage: .headers on|off}} do_test shell1-3.9.2 { catchcmd "test.db" ".header ON" } {0 {}} @@ -357,11 +357,11 @@ do_test shell1-3.9.3 { do_test shell1-3.9.4 { # too many arguments catchcmd "test.db" ".header OFF BAD" -} {1 {Error: unknown command or invalid arguments: "header". Enter ".help" for help}} +} {1 {Usage: .headers on|off}} do_test shell1-3.9.5 { catchcmd "test.db" ".headers" -} {1 {Error: unknown command or invalid arguments: "headers". Enter ".help" for help}} +} {1 {Usage: .headers on|off}} do_test shell1-3.9.6 { catchcmd "test.db" ".headers ON" } {0 {}} @@ -371,7 +371,7 @@ do_test shell1-3.9.7 { do_test shell1-3.9.8 { # too many arguments catchcmd "test.db" ".headers OFF BAD" -} {1 {Error: unknown command or invalid arguments: "headers". Enter ".help" for help}} +} {1 {Usage: .headers on|off}} # .help Show this message do_test shell1-3.10.1 { @@ -393,17 +393,17 @@ do_test shell1-3.10.2 { # .import FILE TABLE Import data from FILE into TABLE do_test shell1-3.11.1 { catchcmd "test.db" ".import" -} {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} +} {1 {Usage: .import FILE TABLE}} do_test shell1-3.11.2 { catchcmd "test.db" ".import FOO" -} {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} -do_test shell1-3.11.2 { - catchcmd "test.db" ".import FOO BAR" -} {1 {Error: no such table: BAR}} +} {1 {Usage: .import FILE TABLE}} +#do_test shell1-3.11.2 { +# catchcmd "test.db" ".import FOO BAR" +#} {1 {Error: no such table: BAR}} do_test shell1-3.11.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" -} {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} +} {1 {Usage: .import FILE TABLE}} # .indices ?TABLE? Show names of all indices # If TABLE specified, only show indices for tables @@ -417,7 +417,7 @@ do_test shell1-3.12.2 { do_test shell1-3.12.3 { # too many arguments catchcmd "test.db" ".indices FOO BAD" -} {1 {Error: unknown command or invalid arguments: "indices". Enter ".help" for help}} +} {1 {Usage: .indices ?LIKE-PATTERN?}} # .mode MODE ?TABLE? Set output mode where MODE is one of: # csv Comma-separated values @@ -430,7 +430,7 @@ do_test shell1-3.12.3 { # tcl TCL list elements do_test shell1-3.13.1 { catchcmd "test.db" ".mode" -} {1 {Error: unknown command or invalid arguments: "mode". Enter ".help" for help}} +} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} do_test shell1-3.13.2 { catchcmd "test.db" ".mode FOO" } {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} @@ -459,9 +459,9 @@ do_test shell1-3.13.10 { catchcmd "test.db" ".mode tcl" } {0 {}} do_test shell1-3.13.11 { - # too many arguments + # extra arguments ignored catchcmd "test.db" ".mode tcl BAD" -} {1 {Error: invalid arguments: "BAD". Enter ".help" for help}} +} {0 {}} # don't allow partial mode type matches do_test shell1-3.13.12 { @@ -472,31 +472,31 @@ do_test shell1-3.13.13 { } {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} do_test shell1-3.13.14 { catchcmd "test.db" ".mode lin" -} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} +} {0 {}} # .nullvalue STRING Print STRING in place of NULL values do_test shell1-3.14.1 { catchcmd "test.db" ".nullvalue" -} {1 {Error: unknown command or invalid arguments: "nullvalue". Enter ".help" for help}} +} {1 {Usage: .nullvalue STRING}} do_test shell1-3.14.2 { catchcmd "test.db" ".nullvalue FOO" } {0 {}} do_test shell1-3.14.3 { # too many arguments catchcmd "test.db" ".nullvalue FOO BAD" -} {1 {Error: unknown command or invalid arguments: "nullvalue". Enter ".help" for help}} +} {1 {Usage: .nullvalue STRING}} # .output FILENAME Send output to FILENAME do_test shell1-3.15.1 { catchcmd "test.db" ".output" -} {1 {Error: unknown command or invalid arguments: "output". Enter ".help" for help}} +} {0 {}} do_test shell1-3.15.2 { catchcmd "test.db" ".output FOO" } {0 {}} do_test shell1-3.15.3 { # too many arguments catchcmd "test.db" ".output FOO BAD" -} {1 {Error: unknown command or invalid arguments: "output". Enter ".help" for help}} +} {1 {Usage: .output FILE}} # .output stdout Send output to the screen do_test shell1-3.16.1 { @@ -505,12 +505,12 @@ do_test shell1-3.16.1 { do_test shell1-3.16.2 { # too many arguments catchcmd "test.db" ".output stdout BAD" -} {1 {Error: unknown command or invalid arguments: "output". Enter ".help" for help}} +} {1 {Usage: .output FILE}} # .prompt MAIN CONTINUE Replace the standard prompts do_test shell1-3.17.1 { catchcmd "test.db" ".prompt" -} {1 {Error: unknown command or invalid arguments: "prompt". Enter ".help" for help}} +} {0 {}} do_test shell1-3.17.2 { catchcmd "test.db" ".prompt FOO" } {0 {}} @@ -520,7 +520,7 @@ do_test shell1-3.17.3 { do_test shell1-3.17.4 { # too many arguments catchcmd "test.db" ".prompt FOO BAR BAD" -} {1 {Error: unknown command or invalid arguments: "prompt". Enter ".help" for help}} +} {0 {}} # .quit Exit this program do_test shell1-3.18.1 { @@ -529,25 +529,25 @@ do_test shell1-3.18.1 { do_test shell1-3.18.2 { # too many arguments catchcmd "test.db" ".quit BAD" -} {1 {Error: unknown command or invalid arguments: "quit". Enter ".help" for help}} +} {0 {}} # .read FILENAME Execute SQL in FILENAME do_test shell1-3.19.1 { catchcmd "test.db" ".read" -} {1 {Error: unknown command or invalid arguments: "read". Enter ".help" for help}} +} {1 {Usage: .read FILE}} do_test shell1-3.19.2 { - file delete -force FOO + forcedelete FOO catchcmd "test.db" ".read FOO" } {1 {Error: cannot open "FOO"}} do_test shell1-3.19.3 { # too many arguments catchcmd "test.db" ".read FOO BAD" -} {1 {Error: unknown command or invalid arguments: "read". Enter ".help" for help}} +} {1 {Usage: .read FILE}} # .restore ?DB? FILE Restore content of DB (default "main") from FILE do_test shell1-3.20.1 { catchcmd "test.db" ".restore" -} {1 {Error: unknown command or invalid arguments: "restore". Enter ".help" for help}} +} {1 {Usage: .restore ?DB? FILE}} do_test shell1-3.20.2 { catchcmd "test.db" ".restore FOO" } {0 {}} @@ -557,7 +557,7 @@ do_test shell1-3.20.3 { do_test shell1-3.20.4 { # too many arguments catchcmd "test.db" ".restore FOO BAR BAD" -} {1 {Error: unknown command or invalid arguments: "restore". Enter ".help" for help}} +} {1 {Usage: .restore ?DB? FILE}} # .schema ?TABLE? Show the CREATE statements # If TABLE specified, only show tables matching @@ -571,7 +571,7 @@ do_test shell1-3.21.2 { do_test shell1-3.21.3 { # too many arguments catchcmd "test.db" ".schema FOO BAD" -} {1 {Error: unknown command or invalid arguments: "schema". Enter ".help" for help}} +} {1 {Usage: .schema ?LIKE-PATTERN?}} do_test shell1-3.21.4 { catchcmd "test.db" { @@ -588,14 +588,17 @@ db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;} # .separator STRING Change separator used by output mode and .import do_test shell1-3.22.1 { catchcmd "test.db" ".separator" -} {1 {Error: unknown command or invalid arguments: "separator". Enter ".help" for help}} +} {1 {Usage: .separator SEPARATOR ?NEWLINE?}} do_test shell1-3.22.2 { catchcmd "test.db" ".separator FOO" } {0 {}} do_test shell1-3.22.3 { + catchcmd "test.db" ".separator ABC XYZ" +} {0 {}} +do_test shell1-3.22.4 { # too many arguments - catchcmd "test.db" ".separator FOO BAD" -} {1 {Error: unknown command or invalid arguments: "separator". Enter ".help" for help}} + catchcmd "test.db" ".separator FOO BAD BAD2" +} {1 {Usage: .separator SEPARATOR ?NEWLINE?}} # .show Show the current values for various settings do_test shell1-3.23.1 { @@ -613,12 +616,12 @@ do_test shell1-3.23.1 { do_test shell1-3.23.2 { # too many arguments catchcmd "test.db" ".show BAD" -} {1 {Error: unknown command or invalid arguments: "show". Enter ".help" for help}} +} {1 {Usage: .show}} # .stats ON|OFF Turn stats on or off do_test shell1-3.23b.1 { catchcmd "test.db" ".stats" -} {1 {Error: unknown command or invalid arguments: "stats". Enter ".help" for help}} +} {1 {Usage: .stats on|off}} do_test shell1-3.23b.2 { catchcmd "test.db" ".stats ON" } {0 {}} @@ -628,7 +631,7 @@ do_test shell1-3.23b.3 { do_test shell1-3.23b.4 { # too many arguments catchcmd "test.db" ".stats OFF BAD" -} {1 {Error: unknown command or invalid arguments: "stats". Enter ".help" for help}} +} {1 {Usage: .stats on|off}} # .tables ?TABLE? List names of tables # If TABLE specified, only list tables matching @@ -642,12 +645,12 @@ do_test shell1-3.24.2 { do_test shell1-3.24.3 { # too many arguments catchcmd "test.db" ".tables FOO BAD" -} {1 {Error: unknown command or invalid arguments: "tables". Enter ".help" for help}} +} {0 {}} # .timeout MS Try opening locked tables for MS milliseconds do_test shell1-3.25.1 { catchcmd "test.db" ".timeout" -} {1 {Error: unknown command or invalid arguments: "timeout". Enter ".help" for help}} +} {0 {}} do_test shell1-3.25.2 { catchcmd "test.db" ".timeout zzz" # this should be treated the same as a '0' timeout @@ -658,12 +661,12 @@ do_test shell1-3.25.3 { do_test shell1-3.25.4 { # too many arguments catchcmd "test.db" ".timeout 1 BAD" -} {1 {Error: unknown command or invalid arguments: "timeout". Enter ".help" for help}} +} {0 {}} # .width NUM NUM ... Set column widths for "column" mode do_test shell1-3.26.1 { catchcmd "test.db" ".width" -} {1 {Error: unknown command or invalid arguments: "width". Enter ".help" for help}} +} {0 {}} do_test shell1-3.26.2 { catchcmd "test.db" ".width xxx" # this should be treated the same as a '0' width for col 1 @@ -689,7 +692,7 @@ do_test shell1-3.26.6 { # .timer ON|OFF Turn the CPU timer measurement on or off do_test shell1-3.27.1 { catchcmd "test.db" ".timer" -} {1 {Error: unknown command or invalid arguments: "timer". Enter ".help" for help}} +} {1 {Usage: .timer on|off}} do_test shell1-3.27.2 { catchcmd "test.db" ".timer ON" } {0 {}} @@ -699,7 +702,7 @@ do_test shell1-3.27.3 { do_test shell1-3.27.4 { # too many arguments catchcmd "test.db" ".timer OFF BAD" -} {1 {Error: unknown command or invalid arguments: "timer". Enter ".help" for help}} +} {1 {Usage: .timer on|off}} do_test shell1-3-28.1 { catchcmd test.db \ @@ -710,10 +713,23 @@ do_test shell1-3-29.1 { catchcmd "test.db" ".print this is a test" } {0 {this is a test}} +# dot-command argument quoting +do_test shell1-3-30.1 { + catchcmd {test.db} {.print "this\"is'a\055test" 'this\"is\\a\055test'} +} {0 {this"is'a-test this\"is\\a\055test}} +do_test shell1-3-31.1 { + catchcmd {test.db} {.print "this\nis\ta\\test" 'this\nis\ta\\test'} +} [list 0 "this\nis\ta\\test this\\nis\\ta\\\\test"] + + # Test the output of the ".dump" command # do_test shell1-4.1 { + db close + forcedelete test.db + sqlite3 db test.db db eval { + PRAGMA encoding=UTF16; CREATE TABLE t1(x); INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f'); } @@ -743,6 +759,14 @@ INSERT INTO t1 VALUES(X'807f');}} # Test the output of ".mode tcl" # do_test shell1-4.3 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA encoding=UTF8; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f'); + } catchcmd test.db ".mode tcl\nselect * from t1;" } {0 {"" "" diff --git a/test/shell2.test b/test/shell2.test index 8260932..def574c 100644 --- a/test/shell2.test +++ b/test/shell2.test @@ -42,7 +42,7 @@ sqlite3 db test.db # Reported on mailing list by Ken Zalewski. # Ticket [aeff892c57]. do_test shell2-1.1.1 { - file delete -force foo.db + forcedelete foo.db set rc [ catchcmd "-batch foo.db" "CREATE TABLE t1(a);" ] set fexist [file exist foo.db] list $rc $fexist @@ -81,7 +81,7 @@ do_test shell2-1.3 { # Test with echo off # NB. whitespace is important do_test shell2-1.4.1 { - file delete -force foo.db + forcedelete foo.db catchcmd "foo.db" {CREATE TABLE foo(a); INSERT INTO foo(a) VALUES(1); SELECT * FROM foo;} @@ -90,7 +90,7 @@ SELECT * FROM foo;} # Test with echo on using command line option # NB. whitespace is important do_test shell2-1.4.2 { - file delete -force foo.db + forcedelete foo.db catchcmd "-echo foo.db" {CREATE TABLE foo(a); INSERT INTO foo(a) VALUES(1); SELECT * FROM foo;} @@ -102,7 +102,7 @@ SELECT * FROM foo; # Test with echo on using dot command # NB. whitespace is important do_test shell2-1.4.3 { - file delete -force foo.db + forcedelete foo.db catchcmd "foo.db" {.echo ON CREATE TABLE foo(a); INSERT INTO foo(a) VALUES(1); @@ -116,7 +116,7 @@ SELECT * FROM foo; # turning off mid- processing. # NB. whitespace is important do_test shell2-1.4.4 { - file delete -force foo.db + forcedelete foo.db catchcmd "foo.db" {.echo ON CREATE TABLE foo(a); .echo OFF @@ -130,7 +130,7 @@ SELECT * FROM foo;} # multiple commands per line. # NB. whitespace is important do_test shell2-1.4.5 { - file delete -force foo.db + forcedelete foo.db catchcmd "foo.db" {.echo ON CREATE TABLE foo1(a); INSERT INTO foo1(a) VALUES(1); @@ -155,13 +155,14 @@ SELECT * FROM foo1; 2 SELECT * FROM foo2; 1 -2}} +2 +}} # Test with echo on and headers on using dot command and # multiple commands per line. # NB. whitespace is important do_test shell2-1.4.6 { - file delete -force foo.db + forcedelete foo.db catchcmd "foo.db" {.echo ON .headers ON CREATE TABLE foo1(a); @@ -192,6 +193,7 @@ a SELECT * FROM foo2; b 1 -2}} +2 +}} finish_test diff --git a/test/shell3.test b/test/shell3.test index d02177b..ce1fd4e 100644 --- a/test/shell3.test +++ b/test/shell3.test @@ -40,7 +40,7 @@ sqlite3 db test.db # Run SQL statement from command line do_test shell3-1.1 { - file delete -force foo.db + forcedelete foo.db set rc [ catchcmd "foo.db \"CREATE TABLE t1(a);\"" ] set fexist [file exist foo.db] list $rc $fexist @@ -70,7 +70,7 @@ do_test shell3-1.7 { # Run SQL file from command line do_test shell3-2.1 { - file delete -force foo.db + forcedelete foo.db set rc [ catchcmd "foo.db" "CREATE TABLE t1(a);" ] set fexist [file exist foo.db] list $rc $fexist diff --git a/test/shell4.test b/test/shell4.test index 5af44c8..c29faf0 100644 --- a/test/shell4.test +++ b/test/shell4.test @@ -63,7 +63,7 @@ do_test shell4-1.2.2 { # .stats ON|OFF Turn stats on or off do_test shell4-1.3.1 { catchcmd "test.db" ".stats" -} {1 {Error: unknown command or invalid arguments: "stats". Enter ".help" for help}} +} {1 {Usage: .stats on|off}} do_test shell4-1.3.2 { catchcmd "test.db" ".stats ON" } {0 {}} @@ -73,7 +73,7 @@ do_test shell4-1.3.3 { do_test shell4-1.3.4 { # too many arguments catchcmd "test.db" ".stats OFF BAD" -} {1 {Error: unknown command or invalid arguments: "stats". Enter ".help" for help}} +} {1 {Usage: .stats on|off}} # NB. whitespace is important do_test shell4-1.4.1 { diff --git a/test/shell5.test b/test/shell5.test index d90cedf..8d740cb 100644 --- a/test/shell5.test +++ b/test/shell5.test @@ -32,7 +32,6 @@ if {![file executable $CLI]} { } db close forcedelete test.db test.db-journal test.db-wal -sqlite3 db test.db #---------------------------------------------------------------------------- # Test cases shell5-1.*: Basic handling of the .import and .separator commands. @@ -41,29 +40,32 @@ sqlite3 db test.db # .import FILE TABLE Import data from FILE into TABLE do_test shell5-1.1.1 { catchcmd "test.db" ".import" -} {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} +} {1 {Usage: .import FILE TABLE}} do_test shell5-1.1.2 { catchcmd "test.db" ".import FOO" -} {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} -do_test shell5-1.1.2 { - catchcmd "test.db" ".import FOO BAR" -} {1 {Error: no such table: BAR}} +} {1 {Usage: .import FILE TABLE}} +#do_test shell5-1.1.2 { +# catchcmd "test.db" ".import FOO BAR" +#} {1 {Error: no such table: BAR}} do_test shell5-1.1.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" -} {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} +} {1 {Usage: .import FILE TABLE}} # .separator STRING Change separator used by output mode and .import -do_test shell1-1.2.1 { +do_test shell5-1.2.1 { catchcmd "test.db" ".separator" -} {1 {Error: unknown command or invalid arguments: "separator". Enter ".help" for help}} -do_test shell1-1.2.2 { - catchcmd "test.db" ".separator FOO" +} {1 {Usage: .separator SEPARATOR ?NEWLINE?}} +do_test shell5-1.2.2 { + catchcmd "test.db" ".separator ONE" } {0 {}} -do_test shell1-1.2.3 { +do_test shell5-1.2.3 { + catchcmd "test.db" ".separator ONE TWO" +} {0 {}} +do_test shell5-1.2.4 { # too many arguments - catchcmd "test.db" ".separator FOO BAD" -} {1 {Error: unknown command or invalid arguments: "separator". Enter ".help" for help}} + catchcmd "test.db" ".separator ONE TWO THREE" +} {1 {Usage: .separator SEPARATOR ?NEWLINE?}} # separator should default to "|" do_test shell5-1.3.1 { @@ -81,14 +83,14 @@ do_test shell5-1.3.2 { # import file doesn't exist do_test shell5-1.4.1 { - file delete -force FOO + forcedelete FOO set res [catchcmd "test.db" {CREATE TABLE t1(a, b); .import FOO t1}] } {1 {Error: cannot open "FOO"}} # empty import file do_test shell5-1.4.2 { - file delete -force shell5.csv + forcedelete shell5.csv set in [open shell5.csv w] close $in set res [catchcmd "test.db" {.import shell5.csv t1 @@ -101,7 +103,7 @@ do_test shell5-1.4.3 { puts $in "1" close $in set res [catchcmd "test.db" {.import shell5.csv t1}] -} {1 {Error: shell5.csv line 1: expected 2 columns of data but found 1}} +} {1 {shell5.csv:1: expected 2 columns but found 1 - filling the rest with NULL}} # import file with 1 row, 3 columns (expecting 2 cols) do_test shell5-1.4.4 { @@ -109,14 +111,15 @@ do_test shell5-1.4.4 { puts $in "1|2|3" close $in set res [catchcmd "test.db" {.import shell5.csv t1}] -} {1 {Error: shell5.csv line 1: expected 2 columns of data but found 3}} +} {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}} # import file with 1 row, 2 columns do_test shell5-1.4.5 { set in [open shell5.csv w] puts $in "1|2" close $in - set res [catchcmd "test.db" {.import shell5.csv t1 + set res [catchcmd "test.db" {DELETE FROM t1; +.import shell5.csv t1 SELECT COUNT(*) FROM t1;}] } {0 1} @@ -197,15 +200,15 @@ SELECT length(b) FROM t1 WHERE a='8';}] # This is limited by SQLITE_MAX_VARIABLE_NUMBER, which defaults to 999. set cols 999 do_test shell5-1.6.1 { - set sql {CREATE TABLE t2(} set data {} for {set i 1} {$i<$cols} {incr i} { - append sql "c$i," + append data "c$i|" + } + append data "c$cols\n"; + for {set i 1} {$i<$cols} {incr i} { append data "$i|" } - append sql "c$cols);" append data "$cols" - catchcmd "test.db" $sql set in [open shell5.csv w] puts $in $data close $in @@ -214,16 +217,160 @@ SELECT COUNT(*) FROM t2;}] } {0 1} # try importing a large number of rows -set rows 999999 +set rows 9999 do_test shell5-1.7.1 { set in [open shell5.csv w] + puts $in a for {set i 1} {$i<=$rows} {incr i} { puts $in $i } close $in - set res [catchcmd "test.db" {CREATE TABLE t3(a); + set res [catchcmd "test.db" {.mode csv .import shell5.csv t3 SELECT COUNT(*) FROM t3;}] } [list 0 $rows] +# Inport from a pipe. (Unix only, as it requires "awk") +if {$tcl_platform(platform)=="unix"} { + do_test shell5-1.8 { + forcedelete test.db + catchcmd test.db {.mode csv +.import "|awk 'END{print \"x,y\";for(i=1;i<=5;i++){print i \",this is \" i}}'" t1 +SELECT * FROM t1;} + } {0 {1,"this is 1" +2,"this is 2" +3,"this is 3" +4,"this is 4" +5,"this is 5"}} +} + +# Import columns containing quoted strings +do_test shell5-1.9 { + set out [open shell5.csv w] + fconfigure $out -translation lf + puts $out {1,"",11} + puts $out {2,"x",22} + puts $out {3,"""",33} + puts $out {4,"hello",44} + puts $out "5,55,\"\"\r" + puts $out {6,66,"x"} + puts $out {7,77,""""} + puts $out {8,88,"hello"} + puts $out {"",9,99} + puts $out {"x",10,110} + puts $out {"""",11,121} + puts $out {"hello",12,132} + close $out + forcedelete test.db + catchcmd test.db {.mode csv + CREATE TABLE t1(a,b,c); +.import shell5.csv t1 + } + sqlite3 db test.db + db eval {SELECT *, '|' FROM t1 ORDER BY rowid} +} {1 {} 11 | 2 x 22 | 3 {"} 33 | 4 hello 44 | 5 55 {} | 6 66 x | 7 77 {"} | 8 88 hello | {} 9 99 | x 10 110 | {"} 11 121 | hello 12 132 |} +db close + +# Import columns containing quoted strings +do_test shell5-1.10 { + set out [open shell5.csv w] + fconfigure $out -translation lf + puts $out {column1,column2,column3,column4} + puts $out "field1,field2,\"x3 \"\"\r\ndata\"\" 3\",field4" + puts $out "x1,x2,\"x3 \"\"\ndata\"\" 3\",x4" + close $out + forcedelete test.db + catchcmd test.db {.mode csv + CREATE TABLE t1(a,b,c,d); +.import shell5.csv t1 + } + sqlite3 db test.db + db eval {SELECT hex(c) FROM t1 ORDER BY rowid} +} {636F6C756D6E33 783320220D0A64617461222033 783320220A64617461222033} + +# Blank last column with \r\n line endings. +do_test shell5-1.11 { + set out [open shell5.csv w] + fconfigure $out -translation binary + puts $out "column1,column2,column3\r" + puts $out "a,b, \r" + puts $out "x,y,\r" + puts $out "p,q,r\r" + close $out + catch {db close} + forcedelete test.db + catchcmd test.db {.mode csv +.import shell5.csv t1 + } + sqlite3 db test.db + db eval {SELECT *, '|' FROM t1} +} {a b { } | x y {} | p q r |} +db close + +#---------------------------------------------------------------------------- +# +reset_db +sqlite3 db test.db +do_test shell5-2.1 { + set fd [open shell5.csv w] + puts $fd ",hello" + close $fd + catchcmd test.db [string trim { +.mode csv +CREATE TABLE t1(a, b); +.import shell5.csv t1 + }] + db eval { SELECT * FROM t1 } +} {{} hello} + +do_test shell5-2.2 { + set fd [open shell5.csv w] + puts $fd {"",hello} + close $fd + catchcmd test.db [string trim { +.mode csv +CREATE TABLE t2(a, b); +.import shell5.csv t2 + }] + db eval { SELECT * FROM t2 } +} {{} hello} + +do_test shell5-2.3 { + set fd [open shell5.csv w] + puts $fd {"x""y",hello} + close $fd + catchcmd test.db [string trim { +.mode csv +CREATE TABLE t3(a, b); +.import shell5.csv t3 + }] + db eval { SELECT * FROM t3 } +} {x\"y hello} + +do_test shell5-2.4 { + set fd [open shell5.csv w] + puts $fd {"xy""",hello} + close $fd + catchcmd test.db [string trim { +.mode csv +CREATE TABLE t4(a, b); +.import shell5.csv t4 + }] + db eval { SELECT * FROM t4 } +} {xy\" hello} + +do_test shell5-2.5 { + set fd [open shell5.csv w] + puts $fd {"one","2"} + puts $fd {} + close $fd + catchcmd test.db [string trim { +.mode csv +CREATE TABLE t4(a, b); +.import shell5.csv t4 + }] + db eval { SELECT * FROM t4 } +} {xy\" hello one 2 {} {}} + + finish_test diff --git a/test/show_speedtest1_rtree.tcl b/test/show_speedtest1_rtree.tcl new file mode 100644 index 0000000..3faa168 --- /dev/null +++ b/test/show_speedtest1_rtree.tcl @@ -0,0 +1,57 @@ +#!/usr/bin/tclsh +# +# This script displays the field of rectangles used by --testset rtree +# of speedtest1. Run this script as follows: +# +# rm test.db +# ./speedtest1 --testset rtree --size 25 test.db +# sqlite3 --separator ' ' test.db 'SELECT * FROM rt1' >data.txt +# wish show_speedtest1_rtree.tcl +# +# The filename "data.txt" is hard coded into this script and so that name +# must be used on lines 3 and 4 above. Elsewhere, different filenames can +# be used. The --size N parameter can be adjusted as desired. +# +package require Tk +set f [open data.txt rb] +set data [read $f] +close $f +canvas .c +frame .b +button .b.b1 -text X-Y -command refill-xy +button .b.b2 -text X-Z -command refill-xz +button .b.b3 -text Y-Z -command refill-yz +pack .b.b1 .b.b2 .b.b3 -side left +pack .c -side top -fill both -expand 1 +pack .b -side top +proc resize_canvas_to_fit {} { + foreach {x0 y0 x1 y1} [.c bbox all] break + set w [expr {$x1-$x0}] + set h [expr {$y1-$y0}] + .c config -width $w -height $h +} +proc refill-xy {} { + .c delete all + foreach {id x0 x1 y0 y1 z0 z1} $::data { + .c create rectangle $x0 $y0 $x1 $y1 + } + .c scale all 0 0 0.05 0.05 + resize_canvas_to_fit +} +proc refill-xz {} { + .c delete all + foreach {id x0 x1 y0 y1 z0 z1} $::data { + .c create rectangle $x0 $z0 $x1 $z1 + } + .c scale all 0 0 0.05 0.05 + resize_canvas_to_fit +} +proc refill-yz {} { + .c delete all + foreach {id x0 x1 y0 y1 z0 z1} $::data { + .c create rectangle $y0 $z0 $y1 $z1 + } + .c scale all 0 0 0.05 0.05 + resize_canvas_to_fit +} +refill-xy diff --git a/test/skipscan1.test b/test/skipscan1.test new file mode 100644 index 0000000..8150b01 --- /dev/null +++ b/test/skipscan1.test @@ -0,0 +1,250 @@ +# 2013-11-13 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests of the "skip-scan" query strategy. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test skipscan1-1.1 { + CREATE TABLE t1(a TEXT, b INT, c INT, d INT); + CREATE INDEX t1abc ON t1(a,b,c); + INSERT INTO t1 VALUES('abc',123,4,5); + INSERT INTO t1 VALUES('abc',234,5,6); + INSERT INTO t1 VALUES('abc',234,6,7); + INSERT INTO t1 VALUES('abc',345,7,8); + INSERT INTO t1 VALUES('def',567,8,9); + INSERT INTO t1 VALUES('def',345,9,10); + INSERT INTO t1 VALUES('bcd',100,6,11); + + /* Fake the sqlite_stat1 table so that the query planner believes + ** the table contains thousands of rows and that the first few + ** columns are not selective. */ + ANALYZE; + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1 VALUES('t1','t1abc','10000 5000 2000 10'); + ANALYZE sqlite_master; +} {} + +# Simple queries that leave the first one or two columns of the +# index unconstrainted. +# +do_execsql_test skipscan1-1.2 { + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {abc 345 7 8 | def 345 9 10 |} +do_execsql_test skipscan1-1.2eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {/* USING INDEX t1abc (ANY(a) AND b=?)*/} +do_execsql_test skipscan1-1.2sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {~/*ORDER BY*/} + +do_execsql_test skipscan1-1.3 { + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a DESC; +} {def 345 9 10 | abc 345 7 8 |} +do_execsql_test skipscan1-1.3eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {/* USING INDEX t1abc (ANY(a) AND b=?)*/} +do_execsql_test skipscan1-1.3sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {~/*ORDER BY*/} + +do_execsql_test skipscan1-1.4 { + SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c; +} {abc 234 6 7 | bcd 100 6 11 |} +do_execsql_test skipscan1-1.4eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c; +} {/* USING INDEX t1abc (ANY(a) AND ANY(b) AND c=?)*/} +do_execsql_test skipscan1-1.4sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c; +} {~/*ORDER BY*/} + +do_execsql_test skipscan1-1.5 { + SELECT a,b,c,d,'|' FROM t1 WHERE c IN (6,7) ORDER BY a, b, c; +} {abc 234 6 7 | abc 345 7 8 | bcd 100 6 11 |} +do_execsql_test skipscan1-1.5eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c IN (6,7) ORDER BY a, b, c; +} {/* USING INDEX t1abc (ANY(a) AND ANY(b) AND c=?)*/} +do_execsql_test skipscan1-1.5sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c IN (6,7) ORDER BY a, b, c; +} {~/*ORDER BY*/} + +do_execsql_test skipscan1-1.6 { + SELECT a,b,c,d,'|' FROM t1 WHERE c BETWEEN 6 AND 7 ORDER BY a, b, c; +} {abc 234 6 7 | abc 345 7 8 | bcd 100 6 11 |} +do_execsql_test skipscan1-1.6eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c BETWEEN 6 AND 7 ORDER BY a, b, c; +} {/* USING INDEX t1abc (ANY(a) AND ANY(b) AND c>? AND c<?)*/} +do_execsql_test skipscan1-1.6sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c BETWEEN 6 AND 7 ORDER BY a, b, c; +} {~/*ORDER BY*/} + +do_execsql_test skipscan1-1.7 { + SELECT a,b,c,d,'|' FROM t1 WHERE b IN (234, 345) AND c BETWEEN 6 AND 7 + ORDER BY a, b; +} {abc 234 6 7 | abc 345 7 8 |} +do_execsql_test skipscan1-1.7eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b IN (234, 345) AND c BETWEEN 6 AND 7 + ORDER BY a, b; +} {/* USING INDEX t1abc (ANY(a) AND b=? AND c>? AND c<?)*/} +do_execsql_test skipscan1-1.7sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b IN (234, 345) AND c BETWEEN 6 AND 7 + ORDER BY a, b; +} {~/*ORDER BY*/} + + +# Joins +# +do_execsql_test skipscan1-1.51 { + CREATE TABLE t1j(x TEXT, y INTEGER); + INSERT INTO t1j VALUES('one',1),('six',6),('ninty-nine',99); + INSERT INTO sqlite_stat1 VALUES('t1j',null,'3'); + ANALYZE sqlite_master; + SELECT x, a, b, c, d, '|' FROM t1j, t1 WHERE c=y ORDER BY +a; +} {six abc 234 6 7 | six bcd 100 6 11 |} +do_execsql_test skipscan1-1.51eqp { + EXPLAIN QUERY PLAN + SELECT x, a, b, c, d, '|' FROM t1j, t1 WHERE c=y ORDER BY +a; +} {/* INDEX t1abc (ANY(a) AND ANY(b) AND c=?)*/} + +do_execsql_test skipscan1-1.52 { + SELECT x, a, b, c, d, '|' FROM t1j LEFT JOIN t1 ON c=y ORDER BY +y, +a; +} {one {} {} {} {} | six abc 234 6 7 | six bcd 100 6 11 | ninty-nine {} {} {} {} |} +do_execsql_test skipscan1-1.52eqp { + EXPLAIN QUERY PLAN + SELECT x, a, b, c, d, '|' FROM t1j LEFT JOIN t1 ON c=y ORDER BY +y, +a; +} {/* INDEX t1abc (ANY(a) AND ANY(b) AND c=?)*/} + +do_execsql_test skipscan1-2.1 { + CREATE TABLE t2(a TEXT, b INT, c INT, d INT, + PRIMARY KEY(a,b,c)); + INSERT INTO t2 SELECT * FROM t1; + + /* Fake the sqlite_stat1 table so that the query planner believes + ** the table contains thousands of rows and that the first few + ** columns are not selective. */ + ANALYZE; + UPDATE sqlite_stat1 SET stat='10000 5000 2000 10' WHERE idx NOT NULL; + ANALYZE sqlite_master; +} {} + +do_execsql_test skipscan1-2.2 { + SELECT a,b,c,d,'|' FROM t2 WHERE b=345 ORDER BY a; +} {abc 345 7 8 | def 345 9 10 |} +do_execsql_test skipscan1-2.2eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t2 WHERE b=345 ORDER BY a; +} {/* USING INDEX sqlite_autoindex_t2_1 (ANY(a) AND b=?)*/} +do_execsql_test skipscan1-2.2sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t2 WHERE b=345 ORDER BY a; +} {~/*ORDER BY*/} + + +do_execsql_test skipscan1-3.1 { + CREATE TABLE t3(a TEXT, b INT, c INT, d INT, + PRIMARY KEY(a,b,c)) WITHOUT ROWID; + INSERT INTO t3 SELECT * FROM t1; + + /* Fake the sqlite_stat1 table so that the query planner believes + ** the table contains thousands of rows and that the first few + ** columns are not selective. */ + ANALYZE; + UPDATE sqlite_stat1 SET stat='10000 5000 2000 10' WHERE idx NOT NULL; + ANALYZE sqlite_master; +} {} + +do_execsql_test skipscan1-3.2 { + SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a; +} {abc 345 7 8 | def 345 9 10 |} +do_execsql_test skipscan1-3.2eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a; +} {/* PRIMARY KEY (ANY(a) AND b=?)*/} +do_execsql_test skipscan1-3.2sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a; +} {~/*ORDER BY*/} + +# Ticket 520070ec7fbaac: Array overrun in the skip-scan optimization +# 2013-12-22 +# +do_execsql_test skipscan1-4.1 { + CREATE TABLE t4(a,b,c,d,e,f,g,h,i); + CREATE INDEX t4all ON t4(a,b,c,d,e,f,g,h); + INSERT INTO t4 VALUES(1,2,3,4,5,6,7,8,9); + ANALYZE; + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1 + VALUES('t4','t4all','655360 163840 40960 10240 2560 640 160 40 10'); + ANALYZE sqlite_master; + SELECT i FROM t4 WHERE a=1; + SELECT i FROM t4 WHERE b=2; + SELECT i FROM t4 WHERE c=3; + SELECT i FROM t4 WHERE d=4; + SELECT i FROM t4 WHERE e=5; + SELECT i FROM t4 WHERE f=6; + SELECT i FROM t4 WHERE g=7; + SELECT i FROM t4 WHERE h=8; +} {9 9 9 9 9 9 9 9} + +# Make sure skip-scan cost computation in the query planner takes into +# account the fact that the seek must occur multiple times. +# +# Prior to 2014-03-10, the costs were computed incorrectly which would +# cause index t5i2 to be used instead of t5i1 on the skipscan1-5.3. +# +do_execsql_test skipscan1-5.1 { + CREATE TABLE t5( + id INTEGER PRIMARY KEY, + loc TEXT, + lang INTEGER, + utype INTEGER, + xa INTEGER, + xd INTEGER, + xh INTEGER + ); + CREATE INDEX t5i1 on t5(loc, xh, xa, utype, lang); + CREATE INDEX t5i2 ON t5(xd,loc,utype,lang); + EXPLAIN QUERY PLAN + SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N'; +} {/.*COVERING INDEX t5i1 .*/} +do_execsql_test skipscan1-5.2 { + ANALYZE; + DELETE FROM sqlite_stat1; + DROP TABLE IF EXISTS sqlite_stat4; + DROP TABLE IF EXISTS sqlite_stat3; + INSERT INTO sqlite_stat1 VALUES('t5','t5i1','2702931 3 2 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('t5','t5i2','2702931 686 2 2 2'); + ANALYZE sqlite_master; +} {} +db cache flush +do_execsql_test skipscan1-5.3 { + EXPLAIN QUERY PLAN + SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N'; +} {/.*COVERING INDEX t5i1 .*/} + + + +finish_test diff --git a/test/skipscan2.test b/test/skipscan2.test new file mode 100644 index 0000000..a42ff2d --- /dev/null +++ b/test/skipscan2.test @@ -0,0 +1,205 @@ +# 2013-11-27 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests of the "skip-scan" query strategy. +# +# The test cases in this file are derived from the description of +# the skip-scan query strategy in the "optoverview.html" document. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test skipscan2-1.1 { + CREATE TABLE people( + name TEXT PRIMARY KEY, + role TEXT NOT NULL, + height INT NOT NULL, -- in cm + CHECK( role IN ('student','teacher') ) + ); + CREATE INDEX people_idx1 ON people(role, height); +} {} +do_execsql_test skipscan2-1.2 { + INSERT INTO people VALUES('Alice','student',156); + INSERT INTO people VALUES('Bob','student',161); + INSERT INTO people VALUES('Cindy','student',155); + INSERT INTO people VALUES('David','student',181); + INSERT INTO people VALUES('Emily','teacher',158); + INSERT INTO people VALUES('Fred','student',163); + INSERT INTO people VALUES('Ginny','student',169); + INSERT INTO people VALUES('Harold','student',172); + INSERT INTO people VALUES('Imma','student',179); + INSERT INTO people VALUES('Jack','student',181); + INSERT INTO people VALUES('Karen','student',163); + INSERT INTO people VALUES('Logan','student',177); + INSERT INTO people VALUES('Megan','teacher',159); + INSERT INTO people VALUES('Nathan','student',163); + INSERT INTO people VALUES('Olivia','student',161); + INSERT INTO people VALUES('Patrick','teacher',180); + INSERT INTO people VALUES('Quiana','student',182); + INSERT INTO people VALUES('Robert','student',159); + INSERT INTO people VALUES('Sally','student',166); + INSERT INTO people VALUES('Tom','student',171); + INSERT INTO people VALUES('Ursula','student',170); + INSERT INTO people VALUES('Vance','student',179); + INSERT INTO people VALUES('Willma','student',175); + INSERT INTO people VALUES('Xavier','teacher',185); + INSERT INTO people VALUES('Yvonne','student',149); + INSERT INTO people VALUES('Zach','student',170); +} + +# Without ANALYZE, a skip-scan is not used +# +do_execsql_test skipscan2-1.3 { + SELECT name FROM people WHERE height>=180 ORDER BY +name; +} {David Jack Patrick Quiana Xavier} +do_execsql_test skipscan2-1.3eqp { + EXPLAIN QUERY PLAN + SELECT name FROM people WHERE height>=180 ORDER BY +name; +} {~/*INDEX people_idx1 */} + +# Now do an ANALYZE. A skip-scan can be used after ANALYZE. +# +do_execsql_test skipscan2-1.4 { + ANALYZE; + -- We do not have enough people above to actually force the use + -- of a skip-scan. So make a manual adjustment to the stat1 table + -- to make it seem like there are many more. + UPDATE sqlite_stat1 SET stat='10000 5000 20' WHERE idx='people_idx1'; + UPDATE sqlite_stat1 SET stat='10000 1' WHERE idx='sqlite_autoindex_people_1'; + ANALYZE sqlite_master; +} +db cache flush +do_execsql_test skipscan2-1.5 { + SELECT name FROM people WHERE height>=180 ORDER BY +name; +} {David Jack Patrick Quiana Xavier} +do_execsql_test skipscan2-1.5eqp { + EXPLAIN QUERY PLAN + SELECT name FROM people WHERE height>=180 ORDER BY +name; +} {/*INDEX people_idx1 */} + +# Same answer with other formulations of the same query +# +do_execsql_test skipscan2-1.6 { + SELECT name FROM people + WHERE role IN (SELECT DISTINCT role FROM people) + AND height>=180 ORDER BY +name; +} {David Jack Patrick Quiana Xavier} +do_execsql_test skipscan2-1.7 { + SELECT name FROM people WHERE role='teacher' AND height>=180 + UNION ALL + SELECT name FROM people WHERE role='student' AND height>=180 + ORDER BY 1; +} {David Jack Patrick Quiana Xavier} + +# Add 8 more people, bringing the total to 34. Then the number of +# duplicates in the left-column of the index will be 17 and +# skip-scan should not be used after an (unfudged) ANALYZE. +# +do_execsql_test skipscan2-1.8 { + INSERT INTO people VALUES('Angie','student',166); + INSERT INTO people VALUES('Brad','student',176); + INSERT INTO people VALUES('Claire','student',168); + INSERT INTO people VALUES('Donald','student',162); + INSERT INTO people VALUES('Elaine','student',177); + INSERT INTO people VALUES('Frazier','student',159); + INSERT INTO people VALUES('Grace','student',179); + INSERT INTO people VALUES('Horace','student',166); + ANALYZE; + SELECT stat FROM sqlite_stat1 WHERE idx='people_idx1'; +} {{34 17 2}} +db cache flush +do_execsql_test skipscan2-1.9 { + SELECT name FROM people WHERE height>=180 ORDER BY +name; +} {David Jack Patrick Quiana Xavier} +do_execsql_test skipscan2-1.9eqp { + EXPLAIN QUERY PLAN + SELECT name FROM people WHERE height>=180 ORDER BY +name; +} {~/*INDEX people_idx1 */} + +# Add 2 more people, bringing the total to 36. Then the number of +# duplicates in the left-column of the index will be 18 and +# skip-scan will be used after an (unfudged) ANALYZE. +# +do_execsql_test skipscan2-1.10 { + INSERT INTO people VALUES('Ingrad','student',155); + INSERT INTO people VALUES('Jacob','student',179); + ANALYZE; + SELECT stat FROM sqlite_stat1 WHERE idx='people_idx1'; +} {{36 18 2}} +db cache flush +do_execsql_test skipscan2-1.11 { + SELECT name FROM people WHERE height>=180 ORDER BY +name; +} {David Jack Patrick Quiana Xavier} +do_execsql_test skipscan2-1.11eqp { + EXPLAIN QUERY PLAN + SELECT name FROM people WHERE height>=180 ORDER BY +name; +} {/*INDEX people_idx1 */} + + +# Repeat using a WITHOUT ROWID table. +# +do_execsql_test skipscan2-2.1 { + CREATE TABLE peoplew( + name TEXT PRIMARY KEY, + role TEXT NOT NULL, + height INT NOT NULL, -- in cm + CHECK( role IN ('student','teacher') ) + ) WITHOUT ROWID; + CREATE INDEX peoplew_idx1 ON peoplew(role, height); + INSERT INTO peoplew(name,role,height) + SELECT name, role, height FROM people; + ALTER TABLE people RENAME TO old_people; + SELECT name FROM peoplew WHERE height>=180 ORDER BY +name; +} {David Jack Patrick Quiana Xavier} +do_execsql_test skipscan2-2.2 { + SELECT name FROM peoplew + WHERE role IN (SELECT DISTINCT role FROM peoplew) + AND height>=180 ORDER BY +name; +} {David Jack Patrick Quiana Xavier} +do_execsql_test skipscan2-2.2 { + SELECT name FROM peoplew WHERE role='teacher' AND height>=180 + UNION ALL + SELECT name FROM peoplew WHERE role='student' AND height>=180 + ORDER BY 1; +} {David Jack Patrick Quiana Xavier} + +# Now do an ANALYZE. A skip-scan can be used after ANALYZE. +# +do_execsql_test skipscan2-2.4 { + ANALYZE; +} +db cache flush +do_execsql_test skipscan2-2.5 { + SELECT name FROM peoplew WHERE height>=180 ORDER BY +name; +} {David Jack Patrick Quiana Xavier} +do_execsql_test skipscan2-2.5eqp { + EXPLAIN QUERY PLAN + SELECT name FROM peoplew WHERE height>=180 ORDER BY +name; +} {/*INDEX peoplew_idx1 */} + +# A skip-scan on a PK index of a WITHOUT ROWID table. +# +do_execsql_test skipscan2-3.1 { + CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID; +} +do_test skipscan2-3.2 { + for {set i 0} {$i < 1000} {incr i} { + execsql { INSERT INTO t3 VALUES($i%2, $i, 'xyz') } + } + execsql { ANALYZE } +} {} +do_eqp_test skipscan2-3.3eqp { + SELECT * FROM t3 WHERE b=42; +} {0 0 0 {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)}} + + +finish_test diff --git a/test/skipscan5.test b/test/skipscan5.test new file mode 100644 index 0000000..5d6d392 --- /dev/null +++ b/test/skipscan5.test @@ -0,0 +1,186 @@ +# 2013-11-13 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests of the "skip-scan" query strategy. In +# particular it tests that stat4 data can be used by a range query +# that uses the skip-scan approach. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix skipscan5 + +ifcapable !stat4 { + finish_test + return +} + +do_execsql_test 1.1 { + CREATE TABLE t1(a INT, b INT, c INT); + CREATE INDEX i1 ON t1(a, b); +} {} + +expr srand(4) +do_test 1.2 { + for {set i 0} {$i < 100} {incr i} { + set a [expr int(rand()*4.0) + 1] + set b [expr int(rand()*20.0) + 1] + execsql { INSERT INTO t1 VALUES($a, $b, NULL) } + } + execsql ANALYZE +} {} + +foreach {tn q res} { + 1 "b = 5" {/*ANY(a) AND b=?*/} + 2 "b > 12 AND b < 16" {/*ANY(a) AND b>? AND b<?*/} + 3 "b > 2 AND b < 16" {/*SCAN TABLE t1*/} + 4 "b > 18 AND b < 25" {/*ANY(a) AND b>? AND b<?*/} + 5 "b > 15" {/*ANY(a) AND b>?*/} + 6 "b > 5" {/*SCAN TABLE t1*/} + 7 "b < 15" {/*SCAN TABLE t1*/} + 8 "b < 5" {/*ANY(a) AND b<?*/} + 9 "5 > b" {/*ANY(a) AND b<?*/} + 10 "b = '5'" {/*ANY(a) AND b=?*/} + 11 "b > '12' AND b < '16'" {/*ANY(a) AND b>? AND b<?*/} + 12 "b > '2' AND b < '16'" {/*SCAN TABLE t1*/} + 13 "b > '18' AND b < '25'" {/*ANY(a) AND b>? AND b<?*/} + 14 "b > '15'" {/*ANY(a) AND b>?*/} + 15 "b > '5'" {/*SCAN TABLE t1*/} + 16 "b < '15'" {/*SCAN TABLE t1*/} + 17 "b < '5'" {/*ANY(a) AND b<?*/} + 18 "'5' > b" {/*ANY(a) AND b<?*/} +} { + set sql "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE $q" + do_execsql_test 1.3.$tn $sql $res +} + + +#------------------------------------------------------------------------- +# Test that range-query/skip-scan estimation works with text values. +# And on UTF-16 databases when there is no UTF-16 collation sequence +# available. +# + +proc test_collate {enc lhs rhs} { + string compare $lhs $rhs +} + +foreach {tn dbenc coll} { + 1 UTF-8 { add_test_collate db 0 0 1 } + 2 UTF-16 { add_test_collate db 1 0 0 } + 3 UTF-8 { add_test_collate db 0 1 0 } +} { + reset_db + eval $coll + + do_execsql_test 2.$tn.1 " PRAGMA encoding = '$dbenc' " + do_execsql_test 2.$tn.2 { + CREATE TABLE t2(a TEXT, b TEXT, c TEXT COLLATE test_collate, d TEXT); + CREATE INDEX i2 ON t2(a, b, c); + } + + set vocab(d) { :) } + set vocab(c) { a b c d e f g h i j k l m n o p q r s t } + set vocab(b) { one two three } + set vocab(a) { sql } + + do_test 2.$tn.3 { + for {set i 0} {$i < 100} {incr i} { + foreach var {a b c d} { + set $var [lindex $vocab($var) [expr $i % [llength $vocab($var)]]] + } + execsql { INSERT INTO t2 VALUES($a, $b, $c, $d) } + } + execsql ANALYZE + } {} + + foreach {tn2 q res} { + 1 { c BETWEEN 'd' AND 'e' } {/*ANY(a) AND ANY(b) AND c>? AND c<?*/} + 2 { c BETWEEN 'b' AND 'r' } {/*SCAN TABLE t2*/} + 3 { c > 'q' } {/*ANY(a) AND ANY(b) AND c>?*/} + 4 { c > 'e' } {/*SCAN TABLE t2*/} + 5 { c < 'q' } {/*SCAN TABLE t2*/} + 4 { c < 'e' } {/*ANY(a) AND ANY(b) AND c<?*/} + } { + set sql "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE $q" + do_execsql_test 2.$tn.$tn2 $sql $res + } + +} + +#------------------------------------------------------------------------- +# Test that range-query/skip-scan estimation works on columns that contain +# a variety of types. +# + +reset_db +do_execsql_test 3.1 { + CREATE TABLE t3(a, b, c); + CREATE INDEX i3 ON t3(a, b); +} + +set values { + NULL NULL NULL + NULL -9567 -9240 + -8725 -8659 -8248.340244520614 + -8208 -7939 -7746.985758536954 + -7057 -6550 -5916 + -5363 -4935.781822975623 -4935.063633571875 + -3518.4554911770183 -2537 -2026 + -1511.2603881914456 -1510.4195994839156 -1435 + -1127.4210136045804 -1045 99 + 1353 1457 1563.2908193223611 + 2245 2286 2552 + 2745.18831295203 2866.279926554429 3075.0468527316334 + 3447 3867 4237.892420141907 + 4335 5052.9775000424015 5232.178240656935 + 5541.784919585003 5749.725576373621 5758 + 6005 6431 7263.477992854769 + 7441 7541 8667.279760663994 + 8857 9199.638673662972 'dl' + 'dro' 'h' 'igprfq' + 'jnbd' 'k' 'kordee' + 'lhwcv' 'mzlb' 'nbjked' + 'nufpo' 'nxqkdq' 'shelln' + 'tvzn' 'wpnt' 'wylf' + 'ydkgu' 'zdb' X'' + X'0a' X'203f6429f1f33f' X'23858e324545e0362b' + X'3f9f8a' X'516f7ddd4b' X'68f1df0930ac6b' + X'9ea60d' X'a06f' X'aefd342a39ce36df' + X'afaa020fe2' X'be201c' X'c47d97b209601e45' +} + +do_test 3.2 { + set c 0 + foreach v $values { + execsql "INSERT INTO t3 VALUES($c % 2, $v, $c)" + incr c + } + execsql ANALYZE +} {} + +foreach {tn q res} { + 1 "b BETWEEN -10000 AND -8000" {/*ANY(a) AND b>? AND b<?*/} + 2 "b BETWEEN -10000 AND 'qqq'" {/*SCAN TABLE t3*/} + 3 "b < X'5555'" {/*SCAN TABLE t3*/} + 4 "b > X'5555'" {/*ANY(a) AND b>?*/} + 5 "b > 'zzz'" {/*ANY(a) AND b>?*/} + 6 "b < 'zzz'" {/*SCAN TABLE t3*/} +} { + set sql "EXPLAIN QUERY PLAN SELECT * FROM t3 WHERE $q" + do_execsql_test 3.3.$tn $sql $res +} + +finish_test + + + + diff --git a/test/softheap1.test b/test/softheap1.test index 6855553..522e455 100644 --- a/test/softheap1.test +++ b/test/softheap1.test @@ -24,10 +24,27 @@ ifcapable !integrityck { return } -sqlite3_soft_heap_limit -1 -sqlite3_soft_heap_limit 0 -sqlite3_soft_heap_limit 5000 +do_test softheap1-1.0 { + execsql {PRAGMA soft_heap_limit} +} [sqlite3_soft_heap_limit -1] do_test softheap1-1.1 { + execsql {PRAGMA soft_heap_limit=123456; PRAGMA soft_heap_limit;} +} {123456 123456} +do_test softheap1-1.2 { + sqlite3_soft_heap_limit -1 +} {123456} +do_test softheap1-1.3 { + execsql {PRAGMA soft_heap_limit(-1); PRAGMA soft_heap_limit;} +} {123456 123456} +do_test softheap1-1.4 { + execsql {PRAGMA soft_heap_limit(0); PRAGMA soft_heap_limit;} +} {0 0} + +sqlite3_soft_heap_limit 5000 +do_test softheap1-2.0 { + execsql {PRAGMA soft_heap_limit} +} {5000} +do_test softheap1-2.1 { execsql { PRAGMA auto_vacuum=1; CREATE TABLE t1(x); diff --git a/test/speedtest1.c b/test/speedtest1.c new file mode 100644 index 0000000..383f580 --- /dev/null +++ b/test/speedtest1.c @@ -0,0 +1,1391 @@ +/* +** A program for performance testing. +** +** The available command-line options are described below: +*/ +static const char zHelp[] = + "Usage: %s [--options] DATABASE\n" + "Options:\n" + " --autovacuum Enable AUTOVACUUM mode\n" + " --cachesize N Set the cache size to N\n" + " --exclusive Enable locking_mode=EXCLUSIVE\n" + " --explain Like --sqlonly but with added EXPLAIN keywords\n" + " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" + " --incrvacuum Enable incremenatal vacuum mode\n" + " --journalmode M Set the journal_mode to MODE\n" + " --key KEY Set the encryption key to KEY\n" + " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" + " --nosync Set PRAGMA synchronous=OFF\n" + " --notnull Add NOT NULL constraints to table columns\n" + " --pagesize N Set the page size to N\n" + " --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n" + " --primarykey Use PRIMARY KEY instead of UNIQUE where appropriate\n" + " --reprepare Reprepare each statement upon every invocation\n" + " --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n" + " --sqlonly No-op. Only show the SQL that would have been run.\n" + " --size N Relative test size. Default=100\n" + " --stats Show statistics at the end\n" + " --testset T Run test-set T\n" + " --trace Turn on SQL tracing\n" + " --utf16be Set text encoding to UTF-16BE\n" + " --utf16le Set text encoding to UTF-16LE\n" + " --verify Run additional verification steps.\n" + " --without-rowid Use WITHOUT ROWID where appropriate\n" +; + + +#include "sqlite3.h" +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> + +/* All global state is held in this structure */ +static struct Global { + sqlite3 *db; /* The open database connection */ + sqlite3_stmt *pStmt; /* Current SQL statement */ + sqlite3_int64 iStart; /* Start-time for the current test */ + sqlite3_int64 iTotal; /* Total time */ + int bWithoutRowid; /* True for --without-rowid */ + int bReprepare; /* True to reprepare the SQL on each rerun */ + int bSqlOnly; /* True to print the SQL once only */ + int bExplain; /* Print SQL with EXPLAIN prefix */ + int bVerify; /* Try to verify that results are correct */ + int szTest; /* Scale factor for test iterations */ + const char *zWR; /* Might be WITHOUT ROWID */ + const char *zNN; /* Might be NOT NULL */ + const char *zPK; /* Might be UNIQUE or PRIMARY KEY */ + unsigned int x, y; /* Pseudo-random number generator state */ + int nResult; /* Size of the current result */ + char zResult[3000]; /* Text of the current result */ +} g; + + +/* Print an error message and exit */ +static void fatal_error(const char *zMsg, ...){ + va_list ap; + va_start(ap, zMsg); + vfprintf(stderr, zMsg, ap); + va_end(ap); + exit(1); +} + +/* +** Return the value of a hexadecimal digit. Return -1 if the input +** is not a hex digit. +*/ +static int hexDigitValue(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; +} + +/* Provide an alternative to sqlite3_stricmp() in older versions of +** SQLite */ +#if SQLITE_VERSION_NUMBER<3007011 +# define sqlite3_stricmp strcmp +#endif + +/* +** Interpret zArg as an integer value, possibly with suffixes. +*/ +static int integerValue(const char *zArg){ + sqlite3_int64 v = 0; + static const struct { char *zSuffix; int iMult; } aMult[] = { + { "KiB", 1024 }, + { "MiB", 1024*1024 }, + { "GiB", 1024*1024*1024 }, + { "KB", 1000 }, + { "MB", 1000000 }, + { "GB", 1000000000 }, + { "K", 1000 }, + { "M", 1000000 }, + { "G", 1000000000 }, + }; + int i; + int isNeg = 0; + if( zArg[0]=='-' ){ + isNeg = 1; + zArg++; + }else if( zArg[0]=='+' ){ + zArg++; + } + if( zArg[0]=='0' && zArg[1]=='x' ){ + int x; + zArg += 2; + while( (x = hexDigitValue(zArg[0]))>=0 ){ + v = (v<<4) + x; + zArg++; + } + }else{ + while( isdigit(zArg[0]) ){ + v = v*10 + zArg[0] - '0'; + zArg++; + } + } + for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){ + if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ + v *= aMult[i].iMult; + break; + } + } + if( v>0x7fffffff ) fatal_error("parameter too large - max 2147483648"); + return (int)(isNeg? -v : v); +} + +/* Return the current wall-clock time, in milliseconds */ +sqlite3_int64 speedtest1_timestamp(void){ + static sqlite3_vfs *clockVfs = 0; + sqlite3_int64 t; + if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); +#if SQLITE_VERSION_NUMBER>=3007000 + if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ + clockVfs->xCurrentTimeInt64(clockVfs, &t); + }else +#endif + { + double r; + clockVfs->xCurrentTime(clockVfs, &r); + t = (sqlite3_int64)(r*86400000.0); + } + return t; +} + +/* Return a pseudo-random unsigned integer */ +unsigned int speedtest1_random(void){ + g.x = (g.x>>1) ^ ((1+~(g.x&1)) & 0xd0000001); + g.y = g.y*1103515245 + 12345; + return g.x ^ g.y; +} + +/* Map the value in within the range of 1...limit into another +** number in a way that is chatic and invertable. +*/ +unsigned swizzle(unsigned in, unsigned limit){ + unsigned out = 0; + while( limit ){ + out = (out<<1) | (in&1); + in >>= 1; + limit >>= 1; + } + return out; +} + +/* Round up a number so that it is a power of two minus one +*/ +unsigned roundup_allones(unsigned limit){ + unsigned m = 1; + while( m<limit ) m = (m<<1)+1; + return m; +} + +/* The speedtest1_numbername procedure below converts its argment (an integer) +** into a string which is the English-language name for that number. +** The returned string should be freed with sqlite3_free(). +** +** Example: +** +** speedtest1_numbername(123) -> "one hundred twenty three" +*/ +int speedtest1_numbername(unsigned int n, char *zOut, int nOut){ + static const char *ones[] = { "zero", "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "ten", "eleven", "twelve", + "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", + "eighteen", "nineteen" }; + static const char *tens[] = { "", "ten", "twenty", "thirty", "forty", + "fifty", "sixty", "seventy", "eighty", "ninety" }; + int i = 0; + + if( n>=1000000000 ){ + i += speedtest1_numbername(n/1000000000, zOut+i, nOut-i); + sqlite3_snprintf(nOut-i, zOut+i, " billion"); + i += (int)strlen(zOut+i); + n = n % 1000000000; + } + if( n>=1000000 ){ + if( i && i<nOut-1 ) zOut[i++] = ' '; + i += speedtest1_numbername(n/1000000, zOut+i, nOut-i); + sqlite3_snprintf(nOut-i, zOut+i, " million"); + i += (int)strlen(zOut+i); + n = n % 1000000; + } + if( n>=1000 ){ + if( i && i<nOut-1 ) zOut[i++] = ' '; + i += speedtest1_numbername(n/1000, zOut+i, nOut-i); + sqlite3_snprintf(nOut-i, zOut+i, " thousand"); + i += (int)strlen(zOut+i); + n = n % 1000; + } + if( n>=100 ){ + if( i && i<nOut-1 ) zOut[i++] = ' '; + sqlite3_snprintf(nOut-i, zOut+i, "%s hundred", ones[n/100]); + i += (int)strlen(zOut+i); + n = n % 100; + } + if( n>=20 ){ + if( i && i<nOut-1 ) zOut[i++] = ' '; + sqlite3_snprintf(nOut-i, zOut+i, "%s", tens[n/10]); + i += (int)strlen(zOut+i); + n = n % 10; + } + if( n>0 ){ + if( i && i<nOut-1 ) zOut[i++] = ' '; + sqlite3_snprintf(nOut-i, zOut+i, "%s", ones[n]); + i += (int)strlen(zOut+i); + } + if( i==0 ){ + sqlite3_snprintf(nOut-i, zOut+i, "zero"); + i += (int)strlen(zOut+i); + } + return i; +} + + +/* Start a new test case */ +#define NAMEWIDTH 60 +static const char zDots[] = + "......................................................................."; +void speedtest1_begin_test(int iTestNum, const char *zTestName, ...){ + int n = (int)strlen(zTestName); + char *zName; + va_list ap; + va_start(ap, zTestName); + zName = sqlite3_vmprintf(zTestName, ap); + va_end(ap); + n = (int)strlen(zName); + if( n>NAMEWIDTH ){ + zName[NAMEWIDTH] = 0; + n = NAMEWIDTH; + } + if( g.bSqlOnly ){ + printf("/* %4d - %s%.*s */\n", iTestNum, zName, NAMEWIDTH-n, zDots); + }else{ + printf("%4d - %s%.*s ", iTestNum, zName, NAMEWIDTH-n, zDots); + fflush(stdout); + } + sqlite3_free(zName); + g.nResult = 0; + g.iStart = speedtest1_timestamp(); + g.x = 0xad131d0b; + g.y = 0x44f9eac8; +} + +/* Complete a test case */ +void speedtest1_end_test(void){ + sqlite3_int64 iElapseTime = speedtest1_timestamp() - g.iStart; + if( !g.bSqlOnly ){ + g.iTotal += iElapseTime; + printf("%4d.%03ds\n", (int)(iElapseTime/1000), (int)(iElapseTime%1000)); + } + if( g.pStmt ){ + sqlite3_finalize(g.pStmt); + g.pStmt = 0; + } +} + +/* Report end of testing */ +void speedtest1_final(void){ + if( !g.bSqlOnly ){ + printf(" TOTAL%.*s %4d.%03ds\n", NAMEWIDTH-5, zDots, + (int)(g.iTotal/1000), (int)(g.iTotal%1000)); + } +} + +/* Print an SQL statement to standard output */ +static void printSql(const char *zSql){ + int n = (int)strlen(zSql); + while( n>0 && (zSql[n-1]==';' || isspace(zSql[n-1])) ){ n--; } + if( g.bExplain ) printf("EXPLAIN "); + printf("%.*s;\n", n, zSql); + if( g.bExplain +#if SQLITE_VERSION_NUMBER>=3007010 + && ( sqlite3_strglob("CREATE *", zSql)==0 + || sqlite3_strglob("DROP *", zSql)==0 + || sqlite3_strglob("ALTER *", zSql)==0 + ) +#endif + ){ + printf("%.*s;\n", n, zSql); + } +} + +/* Run SQL */ +void speedtest1_exec(const char *zFormat, ...){ + va_list ap; + char *zSql; + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( g.bSqlOnly ){ + printSql(zSql); + }else{ + char *zErrMsg = 0; + int rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg); + if( zErrMsg ) fatal_error("SQL error: %s\n%s\n", zErrMsg, zSql); + if( rc!=SQLITE_OK ) fatal_error("exec error: %s\n", sqlite3_errmsg(g.db)); + } + sqlite3_free(zSql); +} + +/* Prepare an SQL statement */ +void speedtest1_prepare(const char *zFormat, ...){ + va_list ap; + char *zSql; + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( g.bSqlOnly ){ + printSql(zSql); + }else{ + int rc; + if( g.pStmt ) sqlite3_finalize(g.pStmt); + rc = sqlite3_prepare_v2(g.db, zSql, -1, &g.pStmt, 0); + if( rc ){ + fatal_error("SQL error: %s\n", sqlite3_errmsg(g.db)); + } + } + sqlite3_free(zSql); +} + +/* Run an SQL statement previously prepared */ +void speedtest1_run(void){ + int i, n, len; + if( g.bSqlOnly ) return; + assert( g.pStmt ); + g.nResult = 0; + while( sqlite3_step(g.pStmt)==SQLITE_ROW ){ + n = sqlite3_column_count(g.pStmt); + for(i=0; i<n; i++){ + const char *z = (const char*)sqlite3_column_text(g.pStmt, i); + if( z==0 ) z = "nil"; + len = (int)strlen(z); + if( g.nResult+len<sizeof(g.zResult)-2 ){ + if( g.nResult>0 ) g.zResult[g.nResult++] = ' '; + memcpy(g.zResult + g.nResult, z, len+1); + g.nResult += len; + } + } + } + if( g.bReprepare ){ + sqlite3_stmt *pNew; + sqlite3_prepare_v2(g.db, sqlite3_sql(g.pStmt), -1, &pNew, 0); + sqlite3_finalize(g.pStmt); + g.pStmt = pNew; + }else{ + sqlite3_reset(g.pStmt); + } +} + +/* The sqlite3_trace() callback function */ +static void traceCallback(void *NotUsed, const char *zSql){ + int n = (int)strlen(zSql); + while( n>0 && (zSql[n-1]==';' || isspace(zSql[n-1])) ) n--; + fprintf(stderr,"%.*s;\n", n, zSql); +} + +/* Substitute random() function that gives the same random +** sequence on each run, for repeatability. */ +static void randomFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **NotUsed2 +){ + sqlite3_result_int64(context, (sqlite3_int64)speedtest1_random()); +} + +/* Estimate the square root of an integer */ +static int est_square_root(int x){ + int y0 = x/2; + int y1; + int n; + for(n=0; y0>0 && n<10; n++){ + y1 = (y0 + x/y0)/2; + if( y1==y0 ) break; + y0 = y1; + } + return y0; +} + +/* +** The main and default testset +*/ +void testset_main(void){ + int i; /* Loop counter */ + int n; /* iteration count */ + int sz; /* Size of the tables */ + int maxb; /* Maximum swizzled value */ + unsigned x1, x2; /* Parameters */ + int len; /* Length of the zNum[] string */ + char zNum[2000]; /* A number name */ + + sz = n = g.szTest*500; + maxb = roundup_allones(sz); + speedtest1_begin_test(100, "%d INSERTs into table with no index", n); + speedtest1_exec("BEGIN"); + speedtest1_exec("CREATE TABLE t1(a INTEGER %s, b INTEGER %s, c TEXT %s);", + g.zNN, g.zNN, g.zNN); + speedtest1_prepare("INSERT INTO t1 VALUES(?1,?2,?3); -- %d times", n); + for(i=1; i<=n; i++){ + x1 = swizzle(i,maxb); + speedtest1_numbername(x1, zNum, sizeof(zNum)); + sqlite3_bind_int64(g.pStmt, 1, (sqlite3_int64)x1); + sqlite3_bind_int(g.pStmt, 2, i); + sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + n = sz; + speedtest1_begin_test(110, "%d ordered INSERTS with one index/PK", n); + speedtest1_exec("BEGIN"); + speedtest1_exec("CREATE TABLE t2(a INTEGER %s %s, b INTEGER %s, c TEXT %s) %s", + g.zNN, g.zPK, g.zNN, g.zNN, g.zWR); + speedtest1_prepare("INSERT INTO t2 VALUES(?1,?2,?3); -- %d times", n); + for(i=1; i<=n; i++){ + x1 = swizzle(i,maxb); + speedtest1_numbername(x1, zNum, sizeof(zNum)); + sqlite3_bind_int(g.pStmt, 1, i); + sqlite3_bind_int64(g.pStmt, 2, (sqlite3_int64)x1); + sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + n = sz; + speedtest1_begin_test(120, "%d unordered INSERTS with one index/PK", n); + speedtest1_exec("BEGIN"); + speedtest1_exec("CREATE TABLE t3(a INTEGER %s %s, b INTEGER %s, c TEXT %s) %s", + g.zNN, g.zPK, g.zNN, g.zNN, g.zWR); + speedtest1_prepare("INSERT INTO t3 VALUES(?1,?2,?3); -- %d times", n); + for(i=1; i<=n; i++){ + x1 = swizzle(i,maxb); + speedtest1_numbername(x1, zNum, sizeof(zNum)); + sqlite3_bind_int(g.pStmt, 2, i); + sqlite3_bind_int64(g.pStmt, 1, (sqlite3_int64)x1); + sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + n = 25; + speedtest1_begin_test(130, "%d SELECTS, numeric BETWEEN, unindexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT count(*), avg(b), sum(length(c)) FROM t1\n" + " WHERE b BETWEEN ?1 AND ?2; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb; + x2 = speedtest1_random()%10 + sz/5000 + x1; + sqlite3_bind_int(g.pStmt, 1, x1); + sqlite3_bind_int(g.pStmt, 2, x2); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + n = 10; + speedtest1_begin_test(140, "%d SELECTS, LIKE, unindexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT count(*), avg(b), sum(length(c)) FROM t1\n" + " WHERE c LIKE ?1; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb; + zNum[0] = '%'; + len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2); + zNum[len] = '%'; + zNum[len+1] = 0; + sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + n = 10; + speedtest1_begin_test(142, "%d SELECTS w/ORDER BY, unindexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT a, b, c FROM t1 WHERE c LIKE ?1\n" + " ORDER BY a; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb; + zNum[0] = '%'; + len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2); + zNum[len] = '%'; + zNum[len+1] = 0; + sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + n = 10; //g.szTest/5; + speedtest1_begin_test(145, "%d SELECTS w/ORDER BY and LIMIT, unindexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT a, b, c FROM t1 WHERE c LIKE ?1\n" + " ORDER BY a LIMIT 10; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb; + zNum[0] = '%'; + len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2); + zNum[len] = '%'; + zNum[len+1] = 0; + sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + speedtest1_begin_test(150, "CREATE INDEX five times"); + speedtest1_exec("BEGIN;"); + speedtest1_exec("CREATE UNIQUE INDEX t1b ON t1(b);"); + speedtest1_exec("CREATE INDEX t1c ON t1(c);"); + speedtest1_exec("CREATE UNIQUE INDEX t2b ON t2(b);"); + speedtest1_exec("CREATE INDEX t2c ON t2(c DESC);"); + speedtest1_exec("CREATE INDEX t3bc ON t3(b,c);"); + speedtest1_exec("COMMIT;"); + speedtest1_end_test(); + + + n = sz/5; + speedtest1_begin_test(160, "%d SELECTS, numeric BETWEEN, indexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT count(*), avg(b), sum(length(c)) FROM t1\n" + " WHERE b BETWEEN ?1 AND ?2; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb; + x2 = speedtest1_random()%10 + sz/5000 + x1; + sqlite3_bind_int(g.pStmt, 1, x1); + sqlite3_bind_int(g.pStmt, 2, x2); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + n = sz/5; + speedtest1_begin_test(161, "%d SELECTS, numeric BETWEEN, PK", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT count(*), avg(b), sum(length(c)) FROM t2\n" + " WHERE a BETWEEN ?1 AND ?2; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb; + x2 = speedtest1_random()%10 + sz/5000 + x1; + sqlite3_bind_int(g.pStmt, 1, x1); + sqlite3_bind_int(g.pStmt, 2, x2); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + n = sz/5; + speedtest1_begin_test(170, "%d SELECTS, text BETWEEN, indexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT count(*), avg(b), sum(length(c)) FROM t1\n" + " WHERE c BETWEEN ?1 AND (?1||'~'); -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = swizzle(i, maxb); + len = speedtest1_numbername(x1, zNum, sizeof(zNum)-1); + sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + n = sz; + speedtest1_begin_test(180, "%d INSERTS with three indexes", n); + speedtest1_exec("BEGIN"); + speedtest1_exec( + "CREATE TABLE t4(\n" + " a INTEGER %s %s,\n" + " b INTEGER %s,\n" + " c TEXT %s\n" + ") %s", + g.zNN, g.zPK, g.zNN, g.zNN, g.zWR); + speedtest1_exec("CREATE INDEX t4b ON t4(b)"); + speedtest1_exec("CREATE INDEX t4c ON t4(c)"); + speedtest1_exec("INSERT INTO t4 SELECT * FROM t1"); + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + n = sz; + speedtest1_begin_test(190, "DELETE and REFILL one table", n); + speedtest1_exec("DELETE FROM t2;"); + speedtest1_exec("INSERT INTO t2 SELECT * FROM t1;"); + speedtest1_end_test(); + + + speedtest1_begin_test(200, "VACUUM"); + speedtest1_exec("VACUUM"); + speedtest1_end_test(); + + + speedtest1_begin_test(210, "ALTER TABLE ADD COLUMN, and query"); + speedtest1_exec("ALTER TABLE t2 ADD COLUMN d DEFAULT 123"); + speedtest1_exec("SELECT sum(d) FROM t2"); + speedtest1_end_test(); + + + n = sz/5; + speedtest1_begin_test(230, "%d UPDATES, numeric BETWEEN, indexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "UPDATE t2 SET d=b*2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb; + x2 = speedtest1_random()%10 + sz/5000 + x1; + sqlite3_bind_int(g.pStmt, 1, x1); + sqlite3_bind_int(g.pStmt, 2, x2); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + n = sz; + speedtest1_begin_test(240, "%d UPDATES of individual rows", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "UPDATE t2 SET d=b*3 WHERE a=?1; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%sz + 1; + sqlite3_bind_int(g.pStmt, 1, x1); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + speedtest1_begin_test(250, "One big UPDATE of the whole %d-row table", sz); + speedtest1_exec("UPDATE t2 SET d=b*4"); + speedtest1_end_test(); + + + speedtest1_begin_test(260, "Query added column after filling"); + speedtest1_exec("SELECT sum(d) FROM t2"); + speedtest1_end_test(); + + + + n = sz/5; + speedtest1_begin_test(270, "%d DELETEs, numeric BETWEEN, indexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "DELETE FROM t2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb + 1; + x2 = speedtest1_random()%10 + sz/5000 + x1; + sqlite3_bind_int(g.pStmt, 1, x1); + sqlite3_bind_int(g.pStmt, 2, x2); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + n = sz; + speedtest1_begin_test(280, "%d DELETEs of individual rows", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "DELETE FROM t3 WHERE a=?1; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%sz + 1; + sqlite3_bind_int(g.pStmt, 1, x1); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + + speedtest1_begin_test(290, "Refill two %d-row tables using REPLACE", sz); + speedtest1_exec("REPLACE INTO t2(a,b,c) SELECT a,b,c FROM t1"); + speedtest1_exec("REPLACE INTO t3(a,b,c) SELECT a,b,c FROM t1"); + speedtest1_end_test(); + + speedtest1_begin_test(300, "Refill a %d-row table using (b&1)==(a&1)", sz); + speedtest1_exec("DELETE FROM t2;"); + speedtest1_exec("INSERT INTO t2(a,b,c)\n" + " SELECT a,b,c FROM t1 WHERE (b&1)==(a&1);"); + speedtest1_exec("INSERT INTO t2(a,b,c)\n" + " SELECT a,b,c FROM t1 WHERE (b&1)<>(a&1);"); + speedtest1_end_test(); + + + n = sz/5; + speedtest1_begin_test(310, "%d four-ways joins", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT t1.c FROM t1, t2, t3, t4\n" + " WHERE t4.a BETWEEN ?1 AND ?2\n" + " AND t3.a=t4.b\n" + " AND t2.a=t3.b\n" + " AND t1.c=t2.c" + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%sz + 1; + x2 = speedtest1_random()%10 + x1 + 4; + sqlite3_bind_int(g.pStmt, 1, x1); + sqlite3_bind_int(g.pStmt, 2, x2); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + speedtest1_begin_test(320, "subquery in result set", n); + speedtest1_prepare( + "SELECT sum(a), max(c),\n" + " avg((SELECT a FROM t2 WHERE 5+t2.b=t1.b) AND rowid<?1), max(c)\n" + " FROM t1 WHERE rowid<?1;" + ); + sqlite3_bind_int(g.pStmt, 1, est_square_root(g.szTest)*50); + speedtest1_run(); + speedtest1_end_test(); + + speedtest1_begin_test(980, "PRAGMA integrity_check"); + speedtest1_exec("PRAGMA integrity_check"); + speedtest1_end_test(); + + + speedtest1_begin_test(990, "ANALYZE"); + speedtest1_exec("ANALYZE"); + speedtest1_end_test(); +} + +/* +** A testset for common table expressions. This exercises code +** for views, subqueries, co-routines, etc. +*/ +void testset_cte(void){ + static const char *azPuzzle[] = { + /* Easy */ + "534...9.." + "67.195..." + ".98....6." + "8...6...3" + "4..8.3..1" + "....2...6" + ".6....28." + "...419..5" + "...28..79", + + /* Medium */ + "53....9.." + "6..195..." + ".98....6." + "8...6...3" + "4..8.3..1" + "....2...6" + ".6....28." + "...419..5" + "....8..79", + + /* Hard */ + "53......." + "6..195..." + ".98....6." + "8...6...3" + "4..8.3..1" + "....2...6" + ".6....28." + "...419..5" + "....8..79", + }; + const char *zPuz; + double rSpacing; + int nElem; + + if( g.szTest<25 ){ + zPuz = azPuzzle[0]; + }else if( g.szTest<70 ){ + zPuz = azPuzzle[1]; + }else{ + zPuz = azPuzzle[2]; + } + speedtest1_begin_test(100, "Sudoku with recursive 'digits'"); + speedtest1_prepare( + "WITH RECURSIVE\n" + " input(sud) AS (VALUES(?1)),\n" + " digits(z,lp) AS (\n" + " VALUES('1', 1)\n" + " UNION ALL\n" + " SELECT CAST(lp+1 AS TEXT), lp+1 FROM digits WHERE lp<9\n" + " ),\n" + " x(s, ind) AS (\n" + " SELECT sud, instr(sud, '.') FROM input\n" + " UNION ALL\n" + " SELECT\n" + " substr(s, 1, ind-1) || z || substr(s, ind+1),\n" + " instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )\n" + " FROM x, digits AS z\n" + " WHERE ind>0\n" + " AND NOT EXISTS (\n" + " SELECT 1\n" + " FROM digits AS lp\n" + " WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)\n" + " OR z.z = substr(s, ((ind-1)%%9) + (lp-1)*9 + 1, 1)\n" + " OR z.z = substr(s, (((ind-1)/3) %% 3) * 3\n" + " + ((ind-1)/27) * 27 + lp\n" + " + ((lp-1) / 3) * 6, 1)\n" + " )\n" + " )\n" + "SELECT s FROM x WHERE ind=0;" + ); + sqlite3_bind_text(g.pStmt, 1, zPuz, -1, SQLITE_STATIC); + speedtest1_run(); + speedtest1_end_test(); + + speedtest1_begin_test(200, "Sudoku with VALUES 'digits'"); + speedtest1_prepare( + "WITH RECURSIVE\n" + " input(sud) AS (VALUES(?1)),\n" + " digits(z,lp) AS (VALUES('1',1),('2',2),('3',3),('4',4),('5',5),\n" + " ('6',6),('7',7),('8',8),('9',9)),\n" + " x(s, ind) AS (\n" + " SELECT sud, instr(sud, '.') FROM input\n" + " UNION ALL\n" + " SELECT\n" + " substr(s, 1, ind-1) || z || substr(s, ind+1),\n" + " instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )\n" + " FROM x, digits AS z\n" + " WHERE ind>0\n" + " AND NOT EXISTS (\n" + " SELECT 1\n" + " FROM digits AS lp\n" + " WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)\n" + " OR z.z = substr(s, ((ind-1)%%9) + (lp-1)*9 + 1, 1)\n" + " OR z.z = substr(s, (((ind-1)/3) %% 3) * 3\n" + " + ((ind-1)/27) * 27 + lp\n" + " + ((lp-1) / 3) * 6, 1)\n" + " )\n" + " )\n" + "SELECT s FROM x WHERE ind=0;" + ); + sqlite3_bind_text(g.pStmt, 1, zPuz, -1, SQLITE_STATIC); + speedtest1_run(); + speedtest1_end_test(); + + rSpacing = 5.0/g.szTest; + speedtest1_begin_test(300, "Mandelbrot Set with spacing=%f", rSpacing); + speedtest1_prepare( + "WITH RECURSIVE \n" + " xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+?1 FROM xaxis WHERE x<1.2),\n" + " yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+?2 FROM yaxis WHERE y<1.0),\n" + " m(iter, cx, cy, x, y) AS (\n" + " SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis\n" + " UNION ALL\n" + " SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m \n" + " WHERE (x*x + y*y) < 4.0 AND iter<28\n" + " ),\n" + " m2(iter, cx, cy) AS (\n" + " SELECT max(iter), cx, cy FROM m GROUP BY cx, cy\n" + " ),\n" + " a(t) AS (\n" + " SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') \n" + " FROM m2 GROUP BY cy\n" + " )\n" + "SELECT group_concat(rtrim(t),x'0a') FROM a;" + ); + sqlite3_bind_double(g.pStmt, 1, rSpacing*.05); + sqlite3_bind_double(g.pStmt, 2, rSpacing); + speedtest1_run(); + speedtest1_end_test(); + + nElem = 10000*g.szTest; + speedtest1_begin_test(400, "EXCEPT operator on %d-element tables", nElem); + speedtest1_prepare( + "WITH RECURSIVE \n" + " t1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM t1 WHERE x<%d),\n" + " t2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM t2 WHERE y<%d)\n" + "SELECT count(x), avg(x) FROM (\n" + " SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1\n" + ");", + nElem, nElem + ); + speedtest1_run(); + speedtest1_end_test(); + +} + +/* Generate two numbers between 1 and mx. The first number is less than +** the second. Usually the numbers are near each other but can sometimes +** be far apart. +*/ +static void twoCoords( + int p1, int p2, /* Parameters adjusting sizes */ + unsigned mx, /* Range of 1..mx */ + unsigned *pX0, unsigned *pX1 /* OUT: write results here */ +){ + unsigned d, x0, x1, span; + + span = mx/100 + 1; + if( speedtest1_random()%3==0 ) span *= p1; + if( speedtest1_random()%p2==0 ) span = mx/2; + d = speedtest1_random()%span + 1; + x0 = speedtest1_random()%(mx-d) + 1; + x1 = x0 + d; + *pX0 = x0; + *pX1 = x1; +} + +/* The following routine is an R-Tree geometry callback. It returns +** true if the object overlaps a slice on the Y coordinate between the +** two values given as arguments. In other words +** +** SELECT count(*) FROM rt1 WHERE id MATCH xslice(10,20); +** +** Is the same as saying: +** +** SELECT count(*) FROM rt1 WHERE y1>=10 AND y0<=20; +*/ +static int xsliceGeometryCallback( + sqlite3_rtree_geometry *p, + int nCoord, + double *aCoord, + int *pRes +){ + *pRes = aCoord[3]>=p->aParam[0] && aCoord[2]<=p->aParam[1]; + return SQLITE_OK; +} + +/* +** A testset for the R-Tree virtual table +*/ +void testset_rtree(int p1, int p2){ + unsigned i, n; + unsigned mxCoord; + unsigned x0, x1, y0, y1, z0, z1; + unsigned iStep; + int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*100 ); + + mxCoord = 15000; + n = g.szTest*100; + speedtest1_begin_test(100, "%d INSERTs into an r-tree", n); + speedtest1_exec("BEGIN"); + speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)"); + speedtest1_prepare("INSERT INTO rt1(id,x0,x1,y0,y1,z0,z1)" + "VALUES(?1,?2,?3,?4,?5,?6,?7)"); + for(i=1; i<=n; i++){ + twoCoords(p1, p2, mxCoord, &x0, &x1); + twoCoords(p1, p2, mxCoord, &y0, &y1); + twoCoords(p1, p2, mxCoord, &z0, &z1); + sqlite3_bind_int(g.pStmt, 1, i); + sqlite3_bind_int(g.pStmt, 2, x0); + sqlite3_bind_int(g.pStmt, 3, x1); + sqlite3_bind_int(g.pStmt, 4, y0); + sqlite3_bind_int(g.pStmt, 5, y1); + sqlite3_bind_int(g.pStmt, 6, z0); + sqlite3_bind_int(g.pStmt, 7, z1); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + speedtest1_begin_test(101, "Copy from rtree to a regular table"); + speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)"); + speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1"); + speedtest1_end_test(); + + n = g.szTest*20; + speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n); + speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2"); + iStep = mxCoord/n; + for(i=0; i<n; i++){ + sqlite3_bind_int(g.pStmt, 1, i*iStep); + sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); + speedtest1_run(); + aCheck[i] = atoi(g.zResult); + } + speedtest1_end_test(); + + if( g.bVerify ){ + n = g.szTest*20; + speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries"); + speedtest1_prepare("SELECT count(*) FROM t1 WHERE x0>=?1 AND x1<=?2"); + iStep = mxCoord/n; + for(i=0; i<n; i++){ + sqlite3_bind_int(g.pStmt, 1, i*iStep); + sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); + speedtest1_run(); + if( aCheck[i]!=atoi(g.zResult) ){ + fatal_error("Count disagree step %d: %d..%d. %d vs %d", + i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult)); + } + } + speedtest1_end_test(); + } + + n = g.szTest*20; + speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n); + speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2"); + iStep = mxCoord/n; + for(i=0; i<n; i++){ + sqlite3_bind_int(g.pStmt, 1, i*iStep); + sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); + speedtest1_run(); + aCheck[i] = atoi(g.zResult); + } + speedtest1_end_test(); + + if( g.bVerify ){ + n = g.szTest*20; + speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries"); + speedtest1_prepare("SELECT count(*) FROM t1 WHERE y1>=?1 AND y0<=?2"); + iStep = mxCoord/n; + for(i=0; i<n; i++){ + sqlite3_bind_int(g.pStmt, 1, i*iStep); + sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); + speedtest1_run(); + if( aCheck[i]!=atoi(g.zResult) ){ + fatal_error("Count disagree step %d: %d..%d. %d vs %d", + i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult)); + } + } + speedtest1_end_test(); + } + + + n = g.szTest*20; + speedtest1_begin_test(125, "%d custom geometry callback queries", n); + sqlite3_rtree_geometry_callback(g.db, "xslice", xsliceGeometryCallback, 0); + speedtest1_prepare("SELECT count(*) FROM rt1 WHERE id MATCH xslice(?1,?2)"); + iStep = mxCoord/n; + for(i=0; i<n; i++){ + sqlite3_bind_int(g.pStmt, 1, i*iStep); + sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); + speedtest1_run(); + if( aCheck[i]!=atoi(g.zResult) ){ + fatal_error("Count disagree step %d: %d..%d. %d vs %d", + i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult)); + } + } + speedtest1_end_test(); + + n = g.szTest*80; + speedtest1_begin_test(130, "%d three-dimensional intersect box queries", n); + speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x1>=?1 AND x0<=?2" + " AND y1>=?1 AND y0<=?2 AND z1>=?1 AND z0<=?2"); + iStep = mxCoord/n; + for(i=0; i<n; i++){ + sqlite3_bind_int(g.pStmt, 1, i*iStep); + sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); + speedtest1_run(); + aCheck[i] = atoi(g.zResult); + } + speedtest1_end_test(); + + n = g.szTest*100; + speedtest1_begin_test(140, "%d rowid queries", n); + speedtest1_prepare("SELECT * FROM rt1 WHERE id=?1"); + for(i=1; i<=n; i++){ + sqlite3_bind_int(g.pStmt, 1, i); + speedtest1_run(); + } + speedtest1_end_test(); +} + +/* +** A testset used for debugging speedtest1 itself. +*/ +void testset_debug1(void){ + unsigned i, n; + unsigned x1, x2; + char zNum[2000]; /* A number name */ + + n = g.szTest; + for(i=1; i<=n; i++){ + x1 = swizzle(i, n); + x2 = swizzle(x1, n); + speedtest1_numbername(x1, zNum, sizeof(zNum)); + printf("%5d %5d %5d %s\n", i, x1, x2, zNum); + } +} + +int main(int argc, char **argv){ + int doAutovac = 0; /* True for --autovacuum */ + int cacheSize = 0; /* Desired cache size. 0 means default */ + int doExclusive = 0; /* True for --exclusive */ + int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ + int doIncrvac = 0; /* True for --incrvacuum */ + const char *zJMode = 0; /* Journal mode */ + const char *zKey = 0; /* Encryption key */ + int nLook = 0, szLook = 0; /* --lookaside configuration */ + int noSync = 0; /* True for --nosync */ + int pageSize = 0; /* Desired page size. 0 means default */ + int nPCache = 0, szPCache = 0;/* --pcache configuration */ + int nScratch = 0, szScratch=0;/* --scratch configuration */ + int showStats = 0; /* True for --stats */ + const char *zTSet = "main"; /* Which --testset torun */ + int doTrace = 0; /* True for --trace */ + const char *zEncoding = 0; /* --utf16be or --utf16le */ + const char *zDbName = 0; /* Name of the test database */ + + void *pHeap = 0; /* Allocated heap space */ + void *pLook = 0; /* Allocated lookaside space */ + void *pPCache = 0; /* Allocated storage for pcache */ + void *pScratch = 0; /* Allocated storage for scratch */ + int iCur, iHi; /* Stats values, current and "highwater" */ + int i; /* Loop counter */ + int rc; /* API return code */ + + /* Process command-line arguments */ + g.zWR = ""; + g.zNN = ""; + g.zPK = "UNIQUE"; + g.szTest = 100; + for(i=1; i<argc; i++){ + const char *z = argv[i]; + if( z[0]=='-' ){ + do{ z++; }while( z[0]=='-' ); + if( strcmp(z,"autovacuum")==0 ){ + doAutovac = 1; + }else if( strcmp(z,"cachesize")==0 ){ + if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); + i++; + cacheSize = integerValue(argv[i]); + }else if( strcmp(z,"exclusive")==0 ){ + doExclusive = 1; + }else if( strcmp(z,"explain")==0 ){ + g.bSqlOnly = 1; + g.bExplain = 1; + }else if( strcmp(z,"heap")==0 ){ + if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]); + nHeap = integerValue(argv[i+1]); + mnHeap = integerValue(argv[i+2]); + i += 2; + }else if( strcmp(z,"incrvacuum")==0 ){ + doIncrvac = 1; + }else if( strcmp(z,"journal")==0 ){ + if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); + zJMode = argv[++i]; + }else if( strcmp(z,"key")==0 ){ + if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); + zKey = argv[++i]; + }else if( strcmp(z,"lookaside")==0 ){ + if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]); + nLook = integerValue(argv[i+1]); + szLook = integerValue(argv[i+2]); + i += 2; + }else if( strcmp(z,"nosync")==0 ){ + noSync = 1; + }else if( strcmp(z,"notnull")==0 ){ + g.zNN = "NOT NULL"; + }else if( strcmp(z,"pagesize")==0 ){ + if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); + pageSize = integerValue(argv[++i]); + }else if( strcmp(z,"pcache")==0 ){ + if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]); + nPCache = integerValue(argv[i+1]); + szPCache = integerValue(argv[i+2]); + i += 2; + }else if( strcmp(z,"primarykey")==0 ){ + g.zPK = "PRIMARY KEY"; + }else if( strcmp(z,"reprepare")==0 ){ + g.bReprepare = 1; + }else if( strcmp(z,"scratch")==0 ){ + if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]); + nScratch = integerValue(argv[i+1]); + szScratch = integerValue(argv[i+2]); + i += 2; + }else if( strcmp(z,"sqlonly")==0 ){ + g.bSqlOnly = 1; + }else if( strcmp(z,"size")==0 ){ + if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); + g.szTest = integerValue(argv[++i]); + }else if( strcmp(z,"stats")==0 ){ + showStats = 1; + }else if( strcmp(z,"testset")==0 ){ + if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); + zTSet = argv[++i]; + }else if( strcmp(z,"trace")==0 ){ + doTrace = 1; + }else if( strcmp(z,"utf16le")==0 ){ + zEncoding = "utf16le"; + }else if( strcmp(z,"utf16be")==0 ){ + zEncoding = "utf16be"; + }else if( strcmp(z,"verify")==0 ){ + g.bVerify = 1; + }else if( strcmp(z,"without-rowid")==0 ){ + g.zWR = "WITHOUT ROWID"; + g.zPK = "PRIMARY KEY"; + }else if( strcmp(z, "help")==0 || strcmp(z,"?")==0 ){ + printf(zHelp, argv[0]); + exit(0); + }else{ + fatal_error("unknown option: %s\nUse \"%s -?\" for help\n", + argv[i], argv[0]); + } + }else if( zDbName==0 ){ + zDbName = argv[i]; + }else{ + fatal_error("surplus argument: %s\nUse \"%s -?\" for help\n", + argv[i], argv[0]); + } + } +#if 0 + if( zDbName==0 ){ + fatal_error(zHelp, argv[0]); + } +#endif + if( nHeap>0 ){ + pHeap = malloc( nHeap ); + if( pHeap==0 ) fatal_error("cannot allocate %d-byte heap\n", nHeap); + rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap); + if( rc ) fatal_error("heap configuration failed: %d\n", rc); + } + if( nPCache>0 && szPCache>0 ){ + pPCache = malloc( nPCache*(sqlite3_int64)szPCache ); + if( pPCache==0 ) fatal_error("cannot allocate %lld-byte pcache\n", + nPCache*(sqlite3_int64)szPCache); + rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache); + if( rc ) fatal_error("pcache configuration failed: %d\n", rc); + } + if( nScratch>0 && szScratch>0 ){ + pScratch = malloc( nScratch*(sqlite3_int64)szScratch ); + if( pScratch==0 ) fatal_error("cannot allocate %lld-byte scratch\n", + nScratch*(sqlite3_int64)szScratch); + rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch); + if( rc ) fatal_error("scratch configuration failed: %d\n", rc); + } + if( nLook>0 ){ + sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); + } + + /* Open the database and the input file */ + if( sqlite3_open(zDbName, &g.db) ){ + fatal_error("Cannot open database file: %s\n", zDbName); + } + if( nLook>0 && szLook>0 ){ + pLook = malloc( nLook*szLook ); + rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook,nLook); + if( rc ) fatal_error("lookaside configuration failed: %d\n", rc); + } + + /* Set database connection options */ + sqlite3_create_function(g.db, "random", 0, SQLITE_UTF8, 0, randomFunc, 0, 0); + if( doTrace ) sqlite3_trace(g.db, traceCallback, 0); + if( zKey ){ + speedtest1_exec("PRAGMA key('%s')", zKey); + } + if( zEncoding ){ + speedtest1_exec("PRAGMA encoding=%s", zEncoding); + } + if( doAutovac ){ + speedtest1_exec("PRAGMA auto_vacuum=FULL"); + }else if( doIncrvac ){ + speedtest1_exec("PRAGMA auto_vacuum=INCREMENTAL"); + } + if( pageSize ){ + speedtest1_exec("PRAGMA page_size=%d", pageSize); + } + if( cacheSize ){ + speedtest1_exec("PRAGMA cache_size=%d", cacheSize); + } + if( noSync ) speedtest1_exec("PRAGMA synchronous=OFF"); + if( doExclusive ){ + speedtest1_exec("PRAGMA locking_mode=EXCLUSIVE"); + } + if( zJMode ){ + speedtest1_exec("PRAGMA journal_mode=%s", zJMode); + } + + if( g.bExplain ) printf(".explain\n.echo on\n"); + if( strcmp(zTSet,"main")==0 ){ + testset_main(); + }else if( strcmp(zTSet,"debug1")==0 ){ + testset_debug1(); + }else if( strcmp(zTSet,"cte")==0 ){ + testset_cte(); + }else if( strcmp(zTSet,"rtree")==0 ){ + testset_rtree(6, 147); + }else{ + fatal_error("unknown testset: \"%s\"\nChoices: main debug1 cte rtree\n", + zTSet); + } + speedtest1_final(); + + /* Database connection statistics printed after both prepared statements + ** have been finalized */ +#if SQLITE_VERSION_NUMBER>=3007009 + if( showStats ){ + sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHi, 0); + printf("-- Lookaside Slots Used: %d (max %d)\n", iCur,iHi); + sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHi, 0); + printf("-- Successful lookasides: %d\n", iHi); + sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur,&iHi,0); + printf("-- Lookaside size faults: %d\n", iHi); + sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur,&iHi,0); + printf("-- Lookaside OOM faults: %d\n", iHi); + sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHi, 0); + printf("-- Pager Heap Usage: %d bytes\n", iCur); + sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHi, 1); + printf("-- Page cache hits: %d\n", iCur); + sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHi, 1); + printf("-- Page cache misses: %d\n", iCur); +#if SQLITE_VERSION_NUMBER>=3007012 + sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHi, 1); + printf("-- Page cache writes: %d\n", iCur); +#endif + sqlite3_db_status(g.db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHi, 0); + printf("-- Schema Heap Usage: %d bytes\n", iCur); + sqlite3_db_status(g.db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHi, 0); + printf("-- Statement Heap Usage: %d bytes\n", iCur); + } +#endif + + sqlite3_close(g.db); + + /* Global memory usage statistics printed after the database connection + ** has closed. Memory usage should be zero at this point. */ + if( showStats ){ + sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHi, 0); + printf("-- Memory Used (bytes): %d (max %d)\n", iCur,iHi); +#if SQLITE_VERSION_NUMBER>=3007000 + sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHi, 0); + printf("-- Outstanding Allocations: %d (max %d)\n", iCur,iHi); +#endif + sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHi, 0); + printf("-- Pcache Overflow Bytes: %d (max %d)\n", iCur,iHi); + sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHi, 0); + printf("-- Scratch Overflow Bytes: %d (max %d)\n", iCur,iHi); + sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHi, 0); + printf("-- Largest Allocation: %d bytes\n",iHi); + sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHi, 0); + printf("-- Largest Pcache Allocation: %d bytes\n",iHi); + sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHi, 0); + printf("-- Largest Scratch Allocation: %d bytes\n", iHi); + } + + /* Release memory */ + free( pLook ); + free( pPCache ); + free( pScratch ); + free( pHeap ); + return 0; +} diff --git a/test/spellfix.test b/test/spellfix.test index dfa487a..21383c2 100644 --- a/test/spellfix.test +++ b/test/spellfix.test @@ -95,6 +95,9 @@ do_test 1.10 { do_execsql_test 1.11 { SELECT next_char('re','vocab','w'); } {a} +do_execsql_test 1.11sub { + SELECT next_char('re','(SELECT w AS x FROM vocab)','x'); +} {a} do_execsql_test 1.12 { SELECT next_char('r','vocab','w'); } {ae} @@ -105,6 +108,22 @@ do_test 1.14 { catchsql {SELECT next_char('','xyzzy','a')} } {1 {no such table: xyzzy}} +do_execsql_test 1.20 { + CREATE TABLE vocab2(w TEXT); + CREATE INDEX vocab2w ON vocab2(w COLLATE nocase); + INSERT INTO vocab2 VALUES('abc'), ('ABD'), ('aBe'), ('AbF'); + SELECT next_char('ab', 'vocab2', 'w', null, 'nocase'); +} {cDeF} +do_execsql_test 1.21 { + SELECT next_char('ab','vocab2','w',null,null); +} {c} +do_execsql_test 1.22 { + SELECT next_char('AB','vocab2','w',null,'NOCASE'); +} {cDeF} +do_execsql_test 1.23 { + SELECT next_char('ab','vocab2','w',null,'binary'); +} {c} + do_execsql_test 2.1 { CREATE VIRTUAL TABLE t2 USING spellfix1; INSERT INTO t2 (word, soundslike) VALUES('school', 'skuul'); @@ -202,6 +221,53 @@ foreach {tn word res} { } $res } +#------------------------------------------------------------------------- +# Try some queries by rowid. +# +do_execsql_test 6.1.1 { + SELECT word FROM t3 WHERE rowid = 10; +} {keener} +do_execsql_test 6.1.2 { + SELECT word, distance FROM t3 WHERE rowid = 10; +} {keener {}} +do_execsql_test 6.1.3 { + SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner'; +} {keener 300} + +ifcapable trace { + proc trace_callback {sql} { + if {[string range $sql 0 2] == "-- "} { + lappend ::trace [string range $sql 3 end] + } + } + + proc do_tracesql_test {tn sql {res {}}} { + set ::trace [list] + uplevel [list do_test $tn [subst -nocommands { + set vals [execsql {$sql}] + concat [set vals] [set ::trace] + }] [list {*}$res]] + } + + db trace trace_callback + do_tracesql_test 6.2.1 { + SELECT word FROM t3 WHERE rowid = 10; + } {keener + {SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?} + } + do_tracesql_test 6.2.2 { + SELECT word, distance FROM t3 WHERE rowid = 10; + } {keener {} + {SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?} + } + do_tracesql_test 6.2.3 { + SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner'; + } {keener 300 + {SELECT id, word, rank, k1 FROM "main"."t3_vocab" WHERE langid=0 AND k2>=?1 AND k2<?2} + } +} + + finish_test diff --git a/test/stat.test b/test/stat.test index ac88f7a..f0447e4 100644 --- a/test/stat.test +++ b/test/stat.test @@ -112,7 +112,17 @@ do_execsql_test stat-2.1 { t3 /00e/ 22 leaf 2 730 276 366 \ t3 /00f/ 23 leaf 2 738 268 370 \ ] -do_execsql_test stat-2.2 { DROP TABLE t3 } {} + +# With every index entry overflowing, make sure no pages are missed +# (other than the locking page which is 64 in this test build.) +# +do_execsql_test stat-2.2 { + UPDATE t3 SET a=a||hex(randomblob(700)); + VACUUM; + SELECT pageno FROM stat EXCEPT SELECT pageno-1 FROM stat; +} {64 136} + +do_execsql_test stat-2.3 { DROP TABLE t3; VACUUM; } {} do_execsql_test stat-3.1 { CREATE TABLE t4(x); @@ -122,22 +132,22 @@ do_execsql_test stat-3.1 { FROM stat WHERE name != 'sqlite_master'; } [list \ i4 / 3 leaf 1 103 905 7782 \ - i4 /000+000000 9 overflow 0 1020 0 0 \ - i4 /000+000001 10 overflow 0 1020 0 0 \ - i4 /000+000002 11 overflow 0 1020 0 0 \ - i4 /000+000003 12 overflow 0 1020 0 0 \ - i4 /000+000004 13 overflow 0 1020 0 0 \ - i4 /000+000005 14 overflow 0 1020 0 0 \ - i4 /000+000006 15 overflow 0 1020 0 0 \ - i4 /000+000007 16 overflow 0 539 481 0 \ + i4 /000+000000 4 overflow 0 1020 0 0 \ + i4 /000+000001 5 overflow 0 1020 0 0 \ + i4 /000+000002 6 overflow 0 1020 0 0 \ + i4 /000+000003 7 overflow 0 1020 0 0 \ + i4 /000+000004 8 overflow 0 1020 0 0 \ + i4 /000+000005 9 overflow 0 1020 0 0 \ + i4 /000+000006 10 overflow 0 1020 0 0 \ + i4 /000+000007 11 overflow 0 539 481 0 \ t4 / 2 leaf 1 640 367 7780 \ - t4 /000+000000 22 overflow 0 1020 0 0 \ - t4 /000+000001 23 overflow 0 1020 0 0 \ - t4 /000+000002 21 overflow 0 1020 0 0 \ - t4 /000+000003 20 overflow 0 1020 0 0 \ - t4 /000+000004 19 overflow 0 1020 0 0 \ - t4 /000+000005 18 overflow 0 1020 0 0 \ - t4 /000+000006 17 overflow 0 1020 0 0 \ + t4 /000+000000 12 overflow 0 1020 0 0 \ + t4 /000+000001 13 overflow 0 1020 0 0 \ + t4 /000+000002 14 overflow 0 1020 0 0 \ + t4 /000+000003 15 overflow 0 1020 0 0 \ + t4 /000+000004 16 overflow 0 1020 0 0 \ + t4 /000+000005 17 overflow 0 1020 0 0 \ + t4 /000+000006 18 overflow 0 1020 0 0 \ ] do_execsql_test stat-4.1 { @@ -146,15 +156,14 @@ do_execsql_test stat-4.1 { SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name = 't5' OR name = 'i5'; } [list \ - i5 / 5 leaf 0 0 1016 0 \ - t5 / 4 leaf 0 0 1016 0 \ + i5 / 20 leaf 0 0 1016 0 \ + t5 / 19 leaf 0 0 1016 0 \ ] db close forcedelete test.db sqlite3 db test.db register_dbstat_vtab db -breakpoint do_execsql_test stat-5.1 { PRAGMA auto_vacuum = OFF; CREATE VIRTUAL TABLE temp.stat USING dbstat; diff --git a/test/subquery.test b/test/subquery.test index f601d3f..93c3f28 100644 --- a/test/subquery.test +++ b/test/subquery.test @@ -241,8 +241,11 @@ do_test subquery-2.5.3.1 { } {10.0} do_test subquery-2.5.3.2 { # Verify that the t4i index was not used in the previous query - set ::sqlite_query_plan -} {t4 {}} + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t4 WHERE x IN (SELECT a FROM t3); + } +} {~/t4i/} do_test subquery-2.5.4 { execsql { DROP TABLE t3; diff --git a/test/syscall.test b/test/syscall.test index 5bf1225..c2d9979 100644 --- a/test/syscall.test +++ b/test/syscall.test @@ -61,6 +61,7 @@ foreach s { fcntl read pread write pwrite fchmod fallocate pread64 pwrite64 unlink openDirectory mkdir rmdir statvfs fchown umask mmap munmap mremap + getpagesize } { if {[test_syscall exists $s]} {lappend syscall_list $s} } diff --git a/test/table.test b/test/table.test index 4826cb9..656884c 100644 --- a/test/table.test +++ b/test/table.test @@ -268,6 +268,7 @@ do_test table-5.2.1 { DROP TABLE IF EXISTS sqlite_stat1; DROP TABLE IF EXISTS sqlite_stat2; DROP TABLE IF EXISTS sqlite_stat3; + DROP TABLE IF EXISTS sqlite_stat4; SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_stat*'; } } {} @@ -463,7 +464,7 @@ do_test table-10.1 { CREATE TABLE t6(a REFERENCES t4(a) NOT NULL); INSERT INTO t6 VALUES(NULL); } -} {1 {t6.a may not be NULL}} +} {1 {NOT NULL constraint failed: t6.a}} do_test table-10.2 { catchsql { DROP TABLE t6; @@ -725,4 +726,51 @@ do_test table-15.2 { execsql {COMMIT} } {} +# Ticket 3a88d85f36704eebe134f7f48aebf00cd6438c1a (2014-08-05) +# The following SQL script segfaults while running the INSERT statement: +# +# CREATE TABLE t1(x DEFAULT(max(1))); +# INSERT INTO t1(rowid) VALUES(1); +# +# The problem appears to be the use of an aggregate function as part of +# the default value for a column. This problem has been in the code since +# at least 2006-01-01 and probably before that. This problem was detected +# and reported on the sqlite-users@sqlite.org mailing list by Zsbán Ambrus. +# +do_execsql_test table-16.1 { + CREATE TABLE t16(x DEFAULT(max(1))); + INSERT INTO t16(x) VALUES(123); + SELECT rowid, x FROM t16; +} {1 123} +do_catchsql_test table-16.2 { + INSERT INTO t16(rowid) VALUES(4); +} {1 {unknown function: max()}} +do_execsql_test table-16.3 { + DROP TABLE t16; + CREATE TABLE t16(x DEFAULT(abs(1))); + INSERT INTO t16(rowid) VALUES(4); + SELECT rowid, x FROM t16; +} {4 1} +do_catchsql_test table-16.4 { + DROP TABLE t16; + CREATE TABLE t16(x DEFAULT(avg(1))); + INSERT INTO t16(rowid) VALUES(123); + SELECT rowid, x FROM t16; +} {1 {unknown function: avg()}} +do_catchsql_test table-16.5 { + DROP TABLE t16; + CREATE TABLE t16(x DEFAULT(count())); + INSERT INTO t16(rowid) VALUES(123); + SELECT rowid, x FROM t16; +} {1 {unknown function: count()}} +do_catchsql_test table-16.6 { + DROP TABLE t16; + CREATE TABLE t16(x DEFAULT(group_concat('x',','))); + INSERT INTO t16(rowid) VALUES(123); + SELECT rowid, x FROM t16; +} {1 {unknown function: group_concat()}} +do_catchsql_test table-16.7 { + INSERT INTO t16 DEFAULT VALUES; +} {1 {unknown function: group_concat()}} + finish_test diff --git a/test/tableopts.test b/test/tableopts.test new file mode 100644 index 0000000..0b2457e --- /dev/null +++ b/test/tableopts.test @@ -0,0 +1,76 @@ +# 2013-10-19 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Test the operation of table-options in the WITH clause of the +# CREATE TABLE statement. +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_test tableopt-1.1 { + catchsql { + CREATE TABLE t1(a,b) WITHOUT rowid; + } +} {1 {PRIMARY KEY missing on table t1}} +do_test tableopt-1.1b { + catchsql { + CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT,b) WITHOUT rowid; + } +} {1 {AUTOINCREMENT not allowed on WITHOUT ROWID tables}} +do_test tableopt-1.2 { + catchsql { + CREATE TABLE t1(a,b) WITHOUT unknown2; + } +} {1 {unknown table option: unknown2}} + +do_execsql_test tableopt-2.1 { + CREATE TABLE t1(a, b, c, PRIMARY KEY(a,b)) WITHOUT rowid; + INSERT INTO t1 VALUES(1,2,3),(2,3,4); + SELECT c FROM t1 WHERE a IN (1,2) ORDER BY b; +} {3 4} +do_test tableopt-2.1.1 { + catchsql { + SELECT rowid, * FROM t1; + } +} {1 {no such column: rowid}} +do_test tableopt-2.1.2 { + catchsql { + SELECT _rowid_, * FROM t1; + } +} {1 {no such column: _rowid_}} +do_test tableopt-2.1.3 { + catchsql { + SELECT oid, * FROM t1; + } +} {1 {no such column: oid}} +do_execsql_test tableopt-2.2 { + VACUUM; + SELECT c FROM t1 WHERE a IN (1,2) ORDER BY b; +} {3 4} +do_test tableopt-2.3 { + sqlite3 db2 test.db + db2 eval {SELECT c FROM t1 WHERE a IN (1,2) ORDER BY b;} +} {3 4} +db2 close + +# Make sure the "without" keyword is still usable as a table or +# column name. +# +do_execsql_test tableopt-3.1 { + CREATE TABLE without(x INTEGER PRIMARY KEY, without TEXT); + INSERT INTO without VALUES(1, 'xyzzy'), (2, 'fizzle'); + SELECT * FROM without WHERE without='xyzzy'; +} {1 xyzzy} + + +finish_test diff --git a/test/temptrigger.test b/test/temptrigger.test index ed1efb9..551c620 100644 --- a/test/temptrigger.test +++ b/test/temptrigger.test @@ -13,6 +13,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix temptrigger ifcapable {!trigger || !shared_cache} { finish_test ; return } @@ -201,4 +202,78 @@ do_test temptrigger-3.4 { catch { db close } catch { db2 close } + +#------------------------------------------------------------------------- +# Test that creating a temp table after a temp trigger on the same name +# has been created is an error. +# +reset_db +do_execsql_test 4.0 { + CREATE TABLE t1(x); + CREATE TEMP TRIGGER tr1 BEFORE INSERT ON t1 BEGIN + SELECT 1,2,3; + END; +} + +do_execsql_test 4.1 { + CREATE TEMP TABLE t1(x); +} + +#------------------------------------------------------------------------- +# Test that no harm is done if the table a temp trigger is attached to is +# deleted by an external connection. +# +reset_db +do_execsql_test 5.0 { + CREATE TABLE t1(x); + CREATE TEMP TRIGGER tr1 BEFORE INSERT ON t1 BEGIN SELECT 1,2,3; END; +} + +do_test 5.1 { + sqlite3 db2 test.db + execsql { DROP TABLE t1 } db2 +} {} + +do_execsql_test 5.2 { + SELECT * FROM sqlite_master; + SELECT * FROM sqlite_temp_master; +} { + trigger tr1 t1 0 + {CREATE TRIGGER tr1 BEFORE INSERT ON t1 BEGIN SELECT 1,2,3; END} +} +db2 close + +#------------------------------------------------------------------------- +# Check that if a second connection creates a table in an attached database +# with the same name as a table in the main database that has a temp +# trigger attached to it nothing goes awry. +# +reset_db +forcedelete test.db2 + +do_execsql_test 6.0 { + CREATE TABLE t1(x); + CREATE TEMP TRIGGER tr1 BEFORE INSERT ON t1 BEGIN + SELECT raise(ABORT, 'error'); + END; + ATTACH 'test.db2' AS aux; +} + +do_test 6.1 { + sqlite3 db2 test.db2 + execsql { CREATE TABLE t1(a, b, c); } db2 +} {} + +do_execsql_test 6.2 { + SELECT type,name,tbl_name,sql FROM aux.sqlite_master; + INSERT INTO aux.t1 VALUES(1,2,3); +} { + table t1 t1 {CREATE TABLE t1(a, b, c)} +} + +do_catchsql_test 6.3 { + INSERT INTO main.t1 VALUES(1); +} {1 error} +db2 close + finish_test diff --git a/test/tester.tcl b/test/tester.tcl index 761a36e..3bf92f2 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -14,7 +14,7 @@ # $Id: tester.tcl,v 1.143 2009/04/09 01:23:49 drh Exp $ #------------------------------------------------------------------------- -# The commands provided by the code in this file to help with creating +# The commands provided by the code in this file to help with creating # test cases are as follows: # # Commands to manipulate the db and the file-system at a high level: @@ -42,6 +42,7 @@ # # Commands to execute/explain SQL statements: # +# memdbsql SQL # stepsql DB SQL # execsql2 SQL # explain_no_trace SQL @@ -58,6 +59,7 @@ # do_test TESTNAME SCRIPT EXPECTED # do_execsql_test TESTNAME SQL EXPECTED # do_catchsql_test TESTNAME SQL EXPECTED +# do_timed_execsql_test TESTNAME SQL EXPECTED # # Commands providing a lower level interface to the global test counters: # @@ -80,7 +82,7 @@ # presql # -# Set the precision of FP arithmatic used by the interpreter. And +# Set the precision of FP arithmatic used by the interpreter. And # configure SQLite to take database file locks on the page that begins # 64KB into the database file instead of the one 1GB in. This means # the code that handles that special case can be tested without creating @@ -90,7 +92,7 @@ set tcl_precision 15 sqlite3_test_control_pending_byte 0x0010000 -# If the pager codec is available, create a wrapper for the [sqlite3] +# If the pager codec is available, create a wrapper for the [sqlite3] # command that appends "-key {xyzzy}" to the command line. i.e. this: # # sqlite3 db test.db @@ -122,7 +124,7 @@ if {[info command sqlite_orig]==""} { } set res } else { - # This command is not opening a new database connection. Pass the + # This command is not opening a new database connection. Pass the # arguments through to the C implementation as the are. # uplevel 1 sqlite_orig $args @@ -291,6 +293,66 @@ proc do_delete_file {force args} { } } +if {$::tcl_platform(platform) eq "windows"} { + proc do_remove_win32_dir {args} { + set nRetry [getFileRetries] ;# Maximum number of retries. + set nDelay [getFileRetryDelay] ;# Delay in ms before retrying. + + foreach dirName $args { + # On windows, sometimes even a [remove_win32_dir] can fail just after + # a directory is emptied. The cause is usually "tag-alongs" - programs + # like anti-virus software, automatic backup tools and various explorer + # extensions that keep a file open a little longer than we expect, + # causing the delete to fail. + # + # The solution is to wait a short amount of time before retrying the + # removal. + # + if {$nRetry > 0} { + for {set i 0} {$i < $nRetry} {incr i} { + set rc [catch { + remove_win32_dir $dirName + } msg] + if {$rc == 0} break + if {$nDelay > 0} { after $nDelay } + } + if {$rc} { error $msg } + } else { + remove_win32_dir $dirName + } + } + } + + proc do_delete_win32_file {args} { + set nRetry [getFileRetries] ;# Maximum number of retries. + set nDelay [getFileRetryDelay] ;# Delay in ms before retrying. + + foreach fileName $args { + # On windows, sometimes even a [delete_win32_file] can fail just after + # a file is closed. The cause is usually "tag-alongs" - programs like + # anti-virus software, automatic backup tools and various explorer + # extensions that keep a file open a little longer than we expect, + # causing the delete to fail. + # + # The solution is to wait a short amount of time before retrying the + # delete. + # + if {$nRetry > 0} { + for {set i 0} {$i < $nRetry} {incr i} { + set rc [catch { + delete_win32_file $fileName + } msg] + if {$rc == 0} break + if {$nDelay > 0} { after $nDelay } + } + if {$rc} { error $msg } + } else { + delete_win32_file $fileName + } + } + } +} + proc execpresql {handle args} { trace remove execution $handle enter [list execpresql $handle] if {[info exists ::G(perm:presql)]} { @@ -312,8 +374,8 @@ proc do_not_use_codec {} { # if {[info exists cmdlinearg]==0} { - # Parse any options specified in the $argv array. This script accepts the - # following options: + # Parse any options specified in the $argv array. This script accepts the + # following options: # # --pause # --soft-heap-limit=NN @@ -342,7 +404,7 @@ if {[info exists cmdlinearg]==0} { foreach a $argv { switch -regexp -- $a { {^-+pause$} { - # Wait for user input before continuing. This is to give the user an + # Wait for user input before continuing. This is to give the user an # opportunity to connect profiling tools to the process. puts -nonewline "Press RETURN to begin..." flush stdout @@ -405,8 +467,8 @@ if {[info exists cmdlinearg]==0} { # Install the malloc layer used to inject OOM errors. And the 'automatic' # extensions. This only needs to be done once for the process. # - sqlite3_shutdown - install_malloc_faultsim 1 + sqlite3_shutdown + install_malloc_faultsim 1 sqlite3_initialize autoinstall_test_functions @@ -516,7 +578,7 @@ proc incr_ntest {} { } -# Invoke the do_test procedure to run a single test +# Invoke the do_test procedure to run a single test # proc do_test {name cmd expected} { global argv cmdlinearg @@ -525,7 +587,7 @@ proc do_test {name cmd expected} { sqlite3_memdebug_settitle $name -# if {[llength $argv]==0} { +# if {[llength $argv]==0} { # set go 1 # } else { # set go 0 @@ -551,12 +613,38 @@ proc do_test {name cmd expected} { fail_test $name } else { if {[regexp {^~?/.*/$} $expected]} { + # "expected" is of the form "/PATTERN/" then the result if correct if + # regular expression PATTERN matches the result. "~/PATTERN/" means + # the regular expression must not match. if {[string index $expected 0]=="~"} { - set re [string map {# {[-0-9.]+}} [string range $expected 2 end-1]] - set ok [expr {![regexp $re $result]}] + set re [string range $expected 2 end-1] + if {[string index $re 0]=="*"} { + # If the regular expression begins with * then treat it as a glob instead + set ok [string match $re $result] + } else { + set re [string map {# {[-0-9.]+}} $re] + set ok [regexp $re $result] + } + set ok [expr {!$ok}] } else { - set re [string map {# {[-0-9.]+}} [string range $expected 1 end-1]] - set ok [regexp $re $result] + set re [string range $expected 1 end-1] + if {[string index $re 0]=="*"} { + # If the regular expression begins with * then treat it as a glob instead + set ok [string match $re $result] + } else { + set re [string map {# {[-0-9.]+}} $re] + set ok [regexp $re $result] + } + } + } elseif {[regexp {^~?\*.*\*$} $expected]} { + # "expected" is of the form "*GLOB*" then the result if correct if + # glob pattern GLOB matches the result. "~/GLOB/" means + # the glob must not match. + if {[string index $expected 0]=="~"} { + set e [string range $expected 1 end] + set ok [expr {![string match $e $result]}] + } else { + set ok [string match $expected $result] } } else { set ok [expr {[string compare $result $expected]==0}] @@ -615,13 +703,13 @@ proc do_realnum_test {name cmd expected} { proc fix_testname {varname} { upvar $varname testname - if {[info exists ::testprefix] + if {[info exists ::testprefix] && [string is digit [string range $testname 0 0]] } { set testname "${::testprefix}-$testname" } } - + proc do_execsql_test {testname sql {result {}}} { fix_testname testname uplevel do_test [list $testname] [list "execsql {$sql}"] [list [list {*}$result]] @@ -630,6 +718,11 @@ proc do_catchsql_test {testname sql result} { fix_testname testname uplevel do_test [list $testname] [list "catchsql {$sql}"] [list $result] } +proc do_timed_execsql_test {testname sql {result {}}} { + fix_testname testname + uplevel do_test [list $testname] [list "execsql_timed {$sql}"]\ + [list [list {*}$result]] +} proc do_eqp_test {name sql res} { uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res] } @@ -707,7 +800,7 @@ proc delete_all_data {} { } } -# Run an SQL script. +# Run an SQL script. # Return the number of microseconds per statement. # proc speed_trial {name numstmt units sql} { @@ -770,6 +863,7 @@ proc speed_trial_summary {name} { # proc finish_test {} { catch {db close} + catch {db1 close} catch {db2 close} catch {db3 close} if {0==[info exists ::SLAVE]} { finalize_testing } @@ -793,9 +887,28 @@ proc finalize_testing {} { set nTest [incr_ntest] set nErr [set_test_counter errors] - puts "$nErr errors out of $nTest tests" - if {$nErr>0} { - puts "Failures on these tests: [set_test_counter fail_list]" + set nKnown 0 + if {[file readable known-problems.txt]} { + set fd [open known-problems.txt] + set content [read $fd] + close $fd + foreach x $content {set known_error($x) 1} + foreach x [set_test_counter fail_list] { + if {[info exists known_error($x)]} {incr nKnown} + } + } + if {$nKnown>0} { + puts "[expr {$nErr-$nKnown}] new errors and $nKnown known errors\ + out of $nTest tests" + } else { + puts "$nErr errors out of $nTest tests" + } + if {$nErr>$nKnown} { + puts -nonewline "Failures on these tests:" + foreach x [set_test_counter fail_list] { + if {![info exists known_error($x)]} {puts -nonewline " $x"} + } + puts "" } foreach warning [set_test_counter warn_list] { puts "Warning: $warning" @@ -907,6 +1020,14 @@ proc execsql {sql {db db}} { # puts "SQL = $sql" uplevel [list $db eval $sql] } +proc execsql_timed {sql {db db}} { + set tm [time { + set x [uplevel [list $db eval $sql]] + } 1] + set tm [lindex $tm 0] + puts -nonewline " ([expr {$tm*0.001}]ms) " + set x +} # Execute SQL and catch exceptions. # @@ -930,6 +1051,87 @@ proc explain {sql {db db}} { } } +proc explain_i {sql {db db}} { + puts "" + puts "addr opcode p1 p2 p3 p4 p5 #" + puts "---- ------------ ------ ------ ------ ---------------- -- -" + + + # Set up colors for the different opcodes. Scheme is as follows: + # + # Red: Opcodes that write to a b-tree. + # Blue: Opcodes that reposition or seek a cursor. + # Green: The ResultRow opcode. + # + if { [catch {fconfigure stdout -mode}]==0 } { + set R "\033\[31;1m" ;# Red fg + set G "\033\[32;1m" ;# Green fg + set B "\033\[34;1m" ;# Red fg + set D "\033\[39;0m" ;# Default fg + } else { + set R "" + set G "" + set B "" + set D "" + } + foreach opcode { + Seek SeekGe SeekGt SeekLe SeekLt NotFound Last Rewind + NoConflict Next Prev VNext VPrev VFilter + } { + set color($opcode) $B + } + foreach opcode {ResultRow} { + set color($opcode) $G + } + foreach opcode {IdxInsert Insert Delete IdxDelete} { + set color($opcode) $R + } + + set bSeenGoto 0 + $db eval "explain $sql" {} { + set x($addr) 0 + set op($addr) $opcode + + if {$opcode == "Goto" && ($bSeenGoto==0 || ($p2 > $addr+10))} { + set linebreak($p2) 1 + set bSeenGoto 1 + } + + if {$opcode=="Next" || $opcode=="Prev" + || $opcode=="VNext" || $opcode=="VPrev" + } { + for {set i $p2} {$i<$addr} {incr i} { + incr x($i) 2 + } + } + + if {$opcode == "Goto" && $p2<$addr && $op($p2)=="Yield"} { + for {set i [expr $p2+1]} {$i<$addr} {incr i} { + incr x($i) 2 + } + } + + if {$opcode == "Halt" && $comment == "End of coroutine"} { + set linebreak([expr $addr+1]) 1 + } + } + + $db eval "explain $sql" {} { + if {[info exists linebreak($addr)]} { + puts "" + } + set I [string repeat " " $x($addr)] + + set col "" + catch { set col $color($opcode) } + + puts [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \ + $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment + ] + } + puts "---- ------------ ------ ------ ------ ---------------- -- -" +} + # Show the VDBE program for an SQL statement but omit the Trace # opcode at the beginning. This procedure can be used to prove # that different SQL statements generate exactly the same VDBE code. @@ -952,6 +1154,15 @@ proc execsql2 {sql} { return $result } +# Use a temporary in-memory database to execute SQL statements +# +proc memdbsql {sql} { + sqlite3 memdb :memory: + set result [memdb eval $sql] + memdb close + return $result +} + # Use the non-callback API to execute multiple SQL statements # proc stepsql {dbptr sql} { @@ -1062,17 +1273,19 @@ proc crashsql {args} { set blocksize "" set crashdelay 1 set prngseed 0 + set opendb { sqlite3 db test.db -vfs crash } set tclbody {} set crashfile "" set dc "" set sql [lindex $args end] - + for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} { set z [lindex $args $ii] set n [string length $z] set z2 [lindex $args [expr $ii+1]] if {$n>1 && [string first $z -delay]==0} {set crashdelay $z2} \ + elseif {$n>1 && [string first $z -opendb]==0} {set opendb $z2} \ elseif {$n>1 && [string first $z -seed]==0} {set prngseed $z2} \ elseif {$n>1 && [string first $z -file]==0} {set crashfile $z2} \ elseif {$n>1 && [string first $z -tclbody]==0} {set tclbody $z2} \ @@ -1085,7 +1298,7 @@ proc crashsql {args} { error "Compulsory option -file missing" } - # $crashfile gets compared to the native filename in + # $crashfile gets compared to the native filename in # cfSync(), which can be different then what TCL uses by # default, so here we force it to the "nativename" format. set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]] @@ -1094,7 +1307,7 @@ proc crashsql {args} { puts $f "sqlite3_crash_enable 1" puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile" puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte" - puts $f "sqlite3 db test.db -vfs crash" + puts $f $opendb # This block sets the cache size of the main database to 10 # pages. This is done in case the build is configured to omit @@ -1102,6 +1315,7 @@ proc crashsql {args} { puts $f {db eval {SELECT * FROM sqlite_master;}} puts $f {set bt [btree_from_db db]} puts $f {btree_set_cache_size $bt 10} + if {$prngseed} { set seed [expr {$prngseed%10007+1}] # puts seed=$seed @@ -1120,7 +1334,7 @@ proc crashsql {args} { set r [catch { exec [info nameofexec] crash.tcl >@stdout } msg] - + # Windows/ActiveState TCL returns a slightly different # error message. We map that to the expected message # so that we don't have to change all of the test @@ -1130,7 +1344,7 @@ proc crashsql {args} { set msg "child process exited abnormally" } } - + lappend r $msg } @@ -1156,7 +1370,7 @@ proc run_ioerr_prep {} { # Usage: do_ioerr_test <test number> <options...> # # This proc is used to implement test cases that check that IO errors -# are correctly handled. The first argument, <test number>, is an integer +# are correctly handled. The first argument, <test number>, is an integer # used to name the tests executed by this proc. Options are as follows: # # -tclprep TCL script to run to prepare test. @@ -1185,7 +1399,7 @@ proc do_ioerr_test {testname args} { # TEMPORARY: For 3.5.9, disable testing of extended result codes. There are # a couple of obscure IO errors that do not return them. set ::ioerropts(-erc) 0 - + # Create a single TCL script from the TCL and SQL specified # as the body of the test. set ::ioerrorbody {} @@ -1209,7 +1423,7 @@ proc do_ioerr_test {testname args} { set ::TN $n incr ::ioerropts(-count) -1 if {$::ioerropts(-count)<0} break - + # Skip this IO error if it was specified with the "-exclude" option. if {[info exists ::ioerropts(-exclude)]} { if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue @@ -1218,7 +1432,7 @@ proc do_ioerr_test {testname args} { restore_prng_state } - # Delete the files test.db and test2.db, then execute the TCL and + # Delete the files test.db and test2.db, then execute the TCL and # SQL (in that order) to prepare for the test case. do_test $testname.$n.1 { run_ioerr_prep @@ -1236,7 +1450,7 @@ proc do_ioerr_test {testname args} { }] $n # Execute the TCL script created for the body of this test. If - # at least N IO operations performed by SQLite as a result of + # at least N IO operations performed by SQLite as a result of # the script, the Nth will fail. do_test $testname.$n.3 { set ::sqlite_io_error_hit 0 @@ -1290,12 +1504,12 @@ proc do_ioerr_test {testname args} { set ::sqlite_io_error_hit 0 set ::sqlite_io_error_pending 0 - # Check that no page references were leaked. There should be - # a single reference if there is still an active transaction, + # Check that no page references were leaked. There should be + # a single reference if there is still an active transaction, # or zero otherwise. # # UPDATE: If the IO error occurs after a 'BEGIN' but before any - # locks are established on database files (i.e. if the error + # locks are established on database files (i.e. if the error # occurs while attempting to detect a hot-journal file), then # there may 0 page references and an active transaction according # to [sqlite3_get_autocommit]. @@ -1311,7 +1525,7 @@ proc do_ioerr_test {testname args} { } {1} } - # If there is an open database handle and no open transaction, + # If there is an open database handle and no open transaction, # and the pager is not running in exclusive-locking mode, # check that the pager is in "unlocked" state. Theoretically, # if a call to xUnlock() failed due to an IO error the underlying @@ -1415,7 +1629,7 @@ proc allcksum {{db db}} { } # Generate a checksum based on the contents of a single database with -# a database connection. The name of the database is $dbname. +# a database connection. The name of the database is $dbname. # Examples of $dbname are "temp" or "main". # proc dbcksum {db dbname} { @@ -1509,8 +1723,8 @@ proc drop_all_tables {{db db}} { #------------------------------------------------------------------------- # If a test script is executed with global variable $::G(perm:name) set to -# "wal", then the tests are run in WAL mode. Otherwise, they should be run -# in rollback mode. The following Tcl procs are used to make this less +# "wal", then the tests are run in WAL mode. Otherwise, they should be run +# in rollback mode. The following Tcl procs are used to make this less # intrusive: # # wal_set_journal_mode ?DB? @@ -1525,9 +1739,9 @@ proc drop_all_tables {{db db}} { # Otherwise (if not running a WAL permutation) this is a no-op. # # wal_is_wal_mode -# +# # Returns true if this test should be run in WAL mode. False otherwise. -# +# proc wal_is_wal_mode {} { expr {[permutation] eq "wal"} } @@ -1628,10 +1842,10 @@ proc slave_test_file {zFile} { } set ::sqlite_open_file_count 0 - # Test that the global "shared-cache" setting was not altered by + # Test that the global "shared-cache" setting was not altered by # the test script. # - ifcapable shared_cache { + ifcapable shared_cache { set res [expr {[sqlite3_enable_shared_cache] == $scs}] do_test ${tail}-sharedcachesetting [list set {} $res] 1 } @@ -1697,5 +1911,11 @@ set AUTOVACUUM $sqlite_options(default_autovacuum) # Make sure the FTS enhanced query syntax is disabled. set sqlite_fts3_enable_parentheses 0 +# During testing, assume that all database files are well-formed. The +# few test cases that deliberately corrupt database files should rescind +# this setting by invoking "database_can_be_corrupt" +# +database_never_corrupt + source $testdir/thread_common.tcl source $testdir/malloc_common.tcl diff --git a/test/tkt-2a5629202f.test b/test/tkt-2a5629202f.test index 037f100..8f09c31 100644 --- a/test/tkt-2a5629202f.test +++ b/test/tkt-2a5629202f.test @@ -46,6 +46,12 @@ do_execsql_test 1.3 { SELECT coalesce(b, 'null') || '/' || c FROM t8 x ORDER BY x.b, x.c } {null/four null/three a/one b/two} +do_execsql_test 1.4 { + DROP INDEX i1; + CREATE UNIQUE INDEX i1 ON t8(b, c); + SELECT coalesce(b, 'null') || '/' || c FROM t8 x ORDER BY x.b, x.c +} {null/four null/three a/one b/two} + #------------------------------------------------------------------------- # @@ -68,4 +74,3 @@ do_test 2.4 { } {sort} finish_test - diff --git a/test/tkt-385a5b56b9.test b/test/tkt-385a5b56b9.test index 8184864..1338435 100644 --- a/test/tkt-385a5b56b9.test +++ b/test/tkt-385a5b56b9.test @@ -35,19 +35,19 @@ do_execsql_test 2.0 { } do_eqp_test 2.1 { SELECT DISTINCT x FROM t2 } { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2x (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2x} } do_eqp_test 2.2 { SELECT DISTINCT y FROM t2 } { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2y (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2y} } do_eqp_test 2.3 { SELECT DISTINCT x, y FROM t2 WHERE y=10 } { - 0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?) (~1 rows)} + 0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)} } do_eqp_test 2.4 { SELECT DISTINCT x, y FROM t2 WHERE x=10 } { - 0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x=?) (~1 rows)} + 0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x=?)} } finish_test diff --git a/test/tkt-3a77c9714e.test b/test/tkt-3a77c9714e.test index 6eaec16..b7d366f 100644 --- a/test/tkt-3a77c9714e.test +++ b/test/tkt-3a77c9714e.test @@ -70,4 +70,3 @@ do_execsql_test 2.2 { finish_test - diff --git a/test/tkt-3fe897352e.test b/test/tkt-3fe897352e.test index deafe48..bc2b203 100644 --- a/test/tkt-3fe897352e.test +++ b/test/tkt-3fe897352e.test @@ -16,9 +16,9 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -
-# The following tests use hex_to_utf16be() and hex_to_utf16le() which
-# which are only available if SQLite is built with UTF16 support.
+ +# The following tests use hex_to_utf16be() and hex_to_utf16le() which +# which are only available if SQLite is built with UTF16 support. ifcapable {!utf16} { finish_test return diff --git a/test/tkt-4a03edc4c8.test b/test/tkt-4a03edc4c8.test index 649f27d..1908bcd 100644 --- a/test/tkt-4a03edc4c8.test +++ b/test/tkt-4a03edc4c8.test @@ -31,7 +31,7 @@ do_test tkt-4a03ed-1.1 { INSERT INTO t1 VALUES(1, 2); COMMIT; } -} {1 {column b is not unique}} +} {1 {UNIQUE constraint failed: t1.b}} do_test tkt-4a03ed-1.2 { db eval { PRAGMA integrity_check; diff --git a/test/tkt-4c86b126f2.test b/test/tkt-4c86b126f2.test new file mode 100644 index 0000000..3c5177e --- /dev/null +++ b/test/tkt-4c86b126f2.test @@ -0,0 +1,49 @@ +# 2014-02-11 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. Specifically, +# it tests that ticket [4c86b126f22ad548fee0125337bdc9366912d9ac]. +# +# When SQLite is compiled using SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4, +# it gets the wrong answer... +# +# The problem was introduced in SQLite 3.8.1. + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test tkt-4c86b126f2-1.1 { + CREATE TABLE nodes( + local_relpath TEXT PRIMARY KEY, + moved_to TEXT + ); + INSERT INTO nodes VALUES('A',NULL); + INSERT INTO nodes VALUES('A/B',NULL); + INSERT INTO nodes VALUES('',NULL); + INSERT INTO nodes VALUES('A/B/C-move',NULL); + INSERT INTO nodes VALUES('A/B/C','A/B/C-move'); + INSERT INTO nodes VALUES('A/B-move',NULL); + INSERT INTO nodes VALUES('A/B-move/C-move',NULL); + INSERT INTO nodes VALUES('A/B-move/C','x'); + SELECT local_relpath, moved_to + FROM nodes + WHERE (local_relpath = 'A/B' OR + ((local_relpath > 'A/B/') AND (local_relpath < 'A/B0'))) + AND moved_to IS NOT NULL; +} {A/B/C A/B/C-move} + +do_execsql_test tkt-4c86b126f2-2.1 { + CREATE TABLE t1(x TEXT UNIQUE, y TEXT UNIQUE, z); + INSERT INTO t1 VALUES('ghi','jkl','y'); + SELECT * FROM t1 WHERE (x='ghi' OR y='jkl') AND z IS NOT NULL; +} {ghi jkl y} + + +finish_test diff --git a/test/tkt-4ef7e3cfca.test b/test/tkt-4ef7e3cfca.test new file mode 100644 index 0000000..fc1efde --- /dev/null +++ b/test/tkt-4ef7e3cfca.test @@ -0,0 +1,68 @@ +# 2014-03-04 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests to verify that ticket [4ef7e3cfca] has been +# fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix tkt-4ef7e3cfca + +do_catchsql_test 1.1 { + CREATE TABLE x(a); + CREATE TRIGGER t AFTER INSERT ON x BEGIN + SELECT * FROM x WHERE abc.a = 1; + END; + INSERT INTO x VALUES('assert'); +} {1 {no such column: abc.a}} + +reset_db +do_execsql_test 2.1 { + CREATE TABLE w(a); + CREATE TABLE x(a); + CREATE TABLE y(a); + CREATE TABLE z(a); + + INSERT INTO x(a) VALUES(5); + INSERT INTO y(a) VALUES(10); + + CREATE TRIGGER t AFTER INSERT ON w BEGIN + INSERT INTO z + SELECT (SELECT x.a + y.a FROM y) FROM x; + END; + INSERT INTO w VALUES('incorrect'); +} +do_execsql_test 2.2 { + SELECT * FROM z; +} {15} + +reset_db +do_execsql_test 3.1 { + CREATE TABLE w(a); + CREATE TABLE x(b); + CREATE TABLE y(a); + CREATE TABLE z(a); + + INSERT INTO x(b) VALUES(5); + INSERT INTO y(a) VALUES(10); + + CREATE TRIGGER t AFTER INSERT ON w BEGIN + INSERT INTO z + SELECT (SELECT x.b + y.a FROM y) FROM x; + END; + INSERT INTO w VALUES('assert'); +} +do_execsql_test 3.2 { + SELECT * FROM z; +} {15} + +finish_test diff --git a/test/tkt-78e04e52ea.test b/test/tkt-78e04e52ea.test index a664ceb..975e5b3 100644 --- a/test/tkt-78e04e52ea.test +++ b/test/tkt-78e04e52ea.test @@ -18,23 +18,23 @@ source $testdir/tester.tcl do_test tkt-78e04-1.0 { execsql { - CREATE TABLE ""("" UNIQUE); + CREATE TABLE ""("" UNIQUE, x CHAR(100)); CREATE TABLE t2(x); - INSERT INTO "" VALUES(1); + INSERT INTO ""("") VALUES(1); INSERT INTO t2 VALUES(2); SELECT * FROM "", t2; } -} {1 2} +} {1 {} 2} do_test tkt-78e04-1.1 { catchsql { - INSERT INTO "" VALUES(1); + INSERT INTO ""("") VALUES(1); } -} {1 {column is not unique}} +} {1 {UNIQUE constraint failed: .}} do_test tkt-78e04-1.2 { execsql { PRAGMA table_info(""); } -} {0 {} {} 0 {} 0} +} {0 {} {} 0 {} 0 1 x CHAR(100) 0 {} 0} do_test tkt-78e04-1.3 { execsql { CREATE INDEX i1 ON ""("" COLLATE nocase); @@ -42,9 +42,9 @@ do_test tkt-78e04-1.3 { } {} do_test tkt-78e04-1.4 { execsql { - EXPLAIN QUERY PLAN SELECT * FROM "" WHERE "" LIKE 'abc%'; + EXPLAIN QUERY PLAN SELECT "" FROM "" WHERE "" LIKE 'abc%'; } -} {0 0 0 {SCAN TABLE USING COVERING INDEX i1 (~500000 rows)}} +} {0 0 0 {SCAN TABLE USING COVERING INDEX i1}} do_test tkt-78e04-1.5 { execsql { DROP TABLE ""; @@ -57,12 +57,12 @@ do_test tkt-78e04-2.1 { CREATE INDEX "" ON t2(x); EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=5; } -} {0 0 0 {SEARCH TABLE t2 USING COVERING INDEX (x=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t2 USING COVERING INDEX (x=?)}} do_test tkt-78e04-2.2 { execsql { DROP INDEX ""; EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=2; } -} {0 0 0 {SCAN TABLE t2 (~100000 rows)}} +} {0 0 0 {SCAN TABLE t2}} finish_test diff --git a/test/tkt-7a31705a7e6.test b/test/tkt-7a31705a7e6.test index 6470122..e3e4029 100644 --- a/test/tkt-7a31705a7e6.test +++ b/test/tkt-7a31705a7e6.test @@ -23,4 +23,3 @@ do_execsql_test tkt-7a31705a7e6-1.1 { CREATE TABLE t2x (b INTEGER PRIMARY KEY); SELECT t1.a FROM ((t1 JOIN t2 ON t1.a=t2.a) AS x JOIN t2x ON x.b=t2x.b) as y; } {} - diff --git a/test/tkt-7bbfb7d442.test b/test/tkt-7bbfb7d442.test index dcb9b16..56d4cae 100644 --- a/test/tkt-7bbfb7d442.test +++ b/test/tkt-7bbfb7d442.test @@ -152,5 +152,3 @@ do_execsql_test 2.3 { finish_test - - diff --git a/test/tkt-80e031a00f.test b/test/tkt-80e031a00f.test index 95372ab..af1d636 100644 --- a/test/tkt-80e031a00f.test +++ b/test/tkt-80e031a00f.test @@ -160,6 +160,10 @@ do_execsql_test tkt-80e031a00f.322 {SELECT 'b' IN t8} 1 do_execsql_test tkt-80e031a00f.323 {SELECT 'c' NOT IN t8} 0 do_execsql_test tkt-80e031a00f.324 {SELECT 'c' IN t8n} 1 do_execsql_test tkt-80e031a00f.325 {SELECT 'd' NOT IN t8n} 0 +do_execsql_test tkt-80e031a00f.326 {SELECT 'a' IN (NULL,'a')} 1 +do_execsql_test tkt-80e031a00f.327 {SELECT 'a' IN (NULL,'b')} {{}} +do_execsql_test tkt-80e031a00f.328 {SELECT 'a' NOT IN (NULL,'a')} 0 +do_execsql_test tkt-80e031a00f.329 {SELECT 'a' NOT IN (NULL,'b')} {{}} # # Row 4: do_execsql_test tkt-80e031a00f.400 {SELECT 1 IN (2,3,4,null)} {{}} diff --git a/test/tkt-868145d012.test b/test/tkt-868145d012.test new file mode 100644 index 0000000..145d159 --- /dev/null +++ b/test/tkt-868145d012.test @@ -0,0 +1,64 @@ +# 2013 March 05 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. Specifically, +# it tests that ticket [868145d012a1] is fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test tkt-868145d012.100 { + CREATE TABLE p ( + id INTEGER PRIMARY KEY, + uid VARCHAR(36), + t INTEGER + ); + + CREATE TABLE pa ( + id INTEGER PRIMARY KEY, + a_uid VARCHAR(36) + ); + + CREATE TABLE a ( + id INTEGER PRIMARY KEY, + uid VARCHAR(36), + t INTEGER + ); + + INSERT INTO pa VALUES(1,'1234'); + INSERT INTO pa VALUES(2,'2345'); + INSERT INTO p VALUES(3,'1234',97); + INSERT INTO p VALUES(4,'1234',98); + INSERT INTO a VALUES(5,'1234',98); + INSERT INTO a VALUES(6,'1234',99); +} {} +do_execsql_test tkt-868145d012.110 { + SELECT DISTINCT pa.id, p.id, a.id + FROM + pa + LEFT JOIN p ON p.uid='1234' + LEFT JOIN a ON a.uid=pa.a_uid + WHERE + a.t=p.t + ; +} {1 4 5} +do_execsql_test tkt-868145d012.120 { + SELECT DISTINCT pa.id, p.id, a.id + FROM + pa + LEFT JOIN p ON p.uid='1234' + LEFT JOIN a ON a.uid=pa.a_uid AND a.t=p.t + ORDER BY 1, 2, 3 + ; +} {1 3 {} 1 4 5 2 3 {} 2 4 {}} + + +finish_test diff --git a/test/tkt-8c63ff0ec.test b/test/tkt-8c63ff0ec.test new file mode 100644 index 0000000..d4aaefd --- /dev/null +++ b/test/tkt-8c63ff0ec.test @@ -0,0 +1,48 @@ +# 2014-02-25 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Test cases to show that ticket [8c63ff0eca81a9132d8d67b31cd6ae9712a2cc6f] +# "Incorrect query result on a UNION ALL" which was caused by using the same +# temporary register in concurrent co-routines, as been fixed. +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix tkt-8c63ff0ec + +do_execsql_test 1.1 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d, e); + INSERT INTO t1 VALUES(1,20,30,40,50),(3,60,70,80,90); + CREATE TABLE t2(x INTEGER PRIMARY KEY); + INSERT INTO t2 VALUES(2); + CREATE TABLE t3(z); + INSERT INTO t3 VALUES(2),(2),(2),(2); + + SELECT a, b+c FROM t1 + UNION ALL + SELECT x, 5 FROM t2 JOIN t3 ON z=x WHERE x=2 + ORDER BY a; +} {1 50 2 5 2 5 2 5 2 5 3 130} +do_execsql_test 1.2 { + SELECT a, b+c+d FROM t1 + UNION ALL + SELECT x, 5 FROM t2 JOIN t3 ON z=x WHERE x=2 + ORDER BY a; +} {1 90 2 5 2 5 2 5 2 5 3 210} +do_execsql_test 1.3 { + SELECT a, b+c+d+e FROM t1 + UNION ALL + SELECT x, 5 FROM t2 JOIN t3 ON z=x WHERE x=2 + ORDER BY a; +} {1 140 2 5 2 5 2 5 2 5 3 300} + +finish_test diff --git a/test/tkt-94c04eaadb.test b/test/tkt-94c04eaadb.test index 0063de6..9de8aea 100644 --- a/test/tkt-94c04eaadb.test +++ b/test/tkt-94c04eaadb.test @@ -44,7 +44,6 @@ do_test tkt-94c94-2.1 { execsql { CREATE TABLE t2(x, y) } db } {} do_test tkt-94c94-2.2 { -breakpoint execsql { INSERT INTO t2 VALUES(1, 2) } db2 } {} do_test tkt-94c94-2.3 { diff --git a/test/tkt-9a8b09f8e6.test b/test/tkt-9a8b09f8e6.test new file mode 100644 index 0000000..d6b22ef --- /dev/null +++ b/test/tkt-9a8b09f8e6.test @@ -0,0 +1,323 @@ +# 2014 June 26 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests to verify that ticket [9a8b09f8e6] has been +# fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix tkt-9a8b09f8e6 + +do_test 1.1 { + execsql { + CREATE TABLE t1(x TEXT); + INSERT INTO t1 VALUES('1'); + } +} {} + +do_test 1.2 { + execsql { + CREATE TABLE t2(x INTEGER); + INSERT INTO t2 VALUES(1); + } +} {} + +do_test 1.3 { + execsql { + CREATE TABLE t3(x REAL); + INSERT INTO t3 VALUES(1.0); + } +} {} + +do_test 1.4 { + execsql { + CREATE TABLE t4(x REAL); + INSERT INTO t4 VALUES(1.11); + } +} {} + +do_test 1.5 { + execsql { + CREATE TABLE t5(x, y); + INSERT INTO t5 VALUES('1', 'one'); + INSERT INTO t5 VALUES(1, 'two'); + INSERT INTO t5 VALUES('1.0', 'three'); + INSERT INTO t5 VALUES(1.0, 'four'); + } +} {} + +do_test 2.1 { + execsql { + SELECT x FROM t1 WHERE x IN (1); + } +} {1} + +do_test 2.2 { + execsql { + SELECT x FROM t1 WHERE x IN (1.0); + } +} {} + +do_test 2.3 { + execsql { + SELECT x FROM t1 WHERE x IN ('1'); + } +} {1} + +do_test 2.4 { + execsql { + SELECT x FROM t1 WHERE x IN ('1.0'); + } +} {} + +do_test 2.5 { + execsql { + SELECT x FROM t1 WHERE 1 IN (x); + } +} {} + +do_test 2.6 { + execsql { + SELECT x FROM t1 WHERE 1.0 IN (x); + } +} {} + +do_test 2.7 { + execsql { + SELECT x FROM t1 WHERE '1' IN (x); + } +} {1} + +do_test 2.8 { + execsql { + SELECT x FROM t1 WHERE '1.0' IN (x); + } +} {} + +do_test 3.1 { + execsql { + SELECT x FROM t2 WHERE x IN (1); + } +} {1} + +do_test 3.2 { + execsql { + SELECT x FROM t2 WHERE x IN (1.0); + } +} {1} + +do_test 3.3 { + execsql { + SELECT x FROM t2 WHERE x IN ('1'); + } +} {1} + +do_test 3.4 { + execsql { + SELECT x FROM t2 WHERE x IN ('1.0'); + } +} {1} + +do_test 3.5 { + execsql { + SELECT x FROM t2 WHERE 1 IN (x); + } +} {1} + +do_test 3.6 { + execsql { + SELECT x FROM t2 WHERE 1.0 IN (x); + } +} {1} + +do_test 3.7 { + execsql { + SELECT x FROM t2 WHERE '1' IN (x); + } +} {} + +do_test 3.8 { + execsql { + SELECT x FROM t2 WHERE '1.0' IN (x); + } +} {} + +do_test 4.1 { + execsql { + SELECT x FROM t3 WHERE x IN (1); + } +} {1.0} + +do_test 4.2 { + execsql { + SELECT x FROM t3 WHERE x IN (1.0); + } +} {1.0} + +do_test 4.3 { + execsql { + SELECT x FROM t3 WHERE x IN ('1'); + } +} {1.0} + +do_test 4.4 { + execsql { + SELECT x FROM t3 WHERE x IN ('1.0'); + } +} {1.0} + +do_test 4.5 { + execsql { + SELECT x FROM t3 WHERE 1 IN (x); + } +} {1.0} + +do_test 4.6 { + execsql { + SELECT x FROM t3 WHERE 1.0 IN (x); + } +} {1.0} + +do_test 4.7 { + execsql { + SELECT x FROM t3 WHERE '1' IN (x); + } +} {} + +do_test 4.8 { + execsql { + SELECT x FROM t3 WHERE '1.0' IN (x); + } +} {} + +do_test 5.1 { + execsql { + SELECT x FROM t4 WHERE x IN (1); + } +} {} + +do_test 5.2 { + execsql { + SELECT x FROM t4 WHERE x IN (1.0); + } +} {} + +do_test 5.3 { + execsql { + SELECT x FROM t4 WHERE x IN ('1'); + } +} {} + +do_test 5.4 { + execsql { + SELECT x FROM t4 WHERE x IN ('1.0'); + } +} {} + +do_test 5.5 { + execsql { + SELECT x FROM t4 WHERE x IN (1.11); + } +} {1.11} + +do_test 5.6 { + execsql { + SELECT x FROM t4 WHERE x IN ('1.11'); + } +} {1.11} + +do_test 5.7 { + execsql { + SELECT x FROM t4 WHERE 1 IN (x); + } +} {} + +do_test 5.8 { + execsql { + SELECT x FROM t4 WHERE 1.0 IN (x); + } +} {} + +do_test 5.9 { + execsql { + SELECT x FROM t4 WHERE '1' IN (x); + } +} {} + +do_test 5.10 { + execsql { + SELECT x FROM t4 WHERE '1.0' IN (x); + } +} {} + +do_test 5.11 { + execsql { + SELECT x FROM t4 WHERE 1.11 IN (x); + } +} {1.11} + +do_test 5.12 { + execsql { + SELECT x FROM t4 WHERE '1.11' IN (x); + } +} {} + +do_test 6.1 { + execsql { + SELECT x, y FROM t5 WHERE x IN (1); + } +} {1 two 1.0 four} + +do_test 6.2 { + execsql { + SELECT x, y FROM t5 WHERE x IN (1.0); + } +} {1 two 1.0 four} + +do_test 6.3 { + execsql { + SELECT x, y FROM t5 WHERE x IN ('1'); + } +} {1 one} + +do_test 6.4 { + execsql { + SELECT x, y FROM t5 WHERE x IN ('1.0'); + } +} {1.0 three} + +do_test 6.5 { + execsql { + SELECT x, y FROM t5 WHERE 1 IN (x); + } +} {1 two 1.0 four} + +do_test 6.6 { + execsql { + SELECT x, y FROM t5 WHERE 1.0 IN (x); + } +} {1 two 1.0 four} + +do_test 6.7 { + execsql { + SELECT x, y FROM t5 WHERE '1' IN (x); + } +} {1 one} + +do_test 6.8 { + execsql { + SELECT x, y FROM t5 WHERE '1.0' IN (x); + } +} {1.0 three} + +finish_test diff --git a/test/tkt-9f2eb3abac.test b/test/tkt-9f2eb3abac.test new file mode 100644 index 0000000..5b93733 --- /dev/null +++ b/test/tkt-9f2eb3abac.test @@ -0,0 +1,79 @@ + +# 2013 August 29 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +set ::testprefix tkt-9f2eb3abac + +do_execsql_test 1.1 { + CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,d,e)); + SELECT * FROM t1 WHERE a=? AND b=? AND c=? AND d=? AND e=?; +} {} + +do_execsql_test 1.2 { + CREATE TABLE "a" ( + "b" integer NOT NULL, + "c" integer NOT NULL, + PRIMARY KEY ("b", "c") + ); + + CREATE TABLE "d" ( + "e" integer NOT NULL, + "g" integer NOT NULL, + "f" integer NOT NULL, + "h" integer NOT NULL, + "i" character(10) NOT NULL, + "j" int, + PRIMARY KEY ("e", "g", "f", "h") + ); + + CREATE TABLE "d_to_a" ( + "f_e" integer NOT NULL, + "f_g" integer NOT NULL, + "f_f" integer NOT NULL, + "f_h" integer NOT NULL, + "t_b" integer NOT NULL, + "t_c" integer NOT NULL, + "r" character NOT NULL, + "s" integer, + PRIMARY KEY ("f_e", "f_g", "f_f", "f_h", "t_b", "t_c") + ); + + INSERT INTO d (g, e, h, f, j, i) VALUES ( 1, 1, 1, 1, 1, 1 ); + INSERT INTO a (b, c) VALUES ( 1, 1 ); + INSERT INTO d_to_a VALUES (1, 1, 1, 1, 1, 1, 1, 1); + + DELETE FROM d_to_a + WHERE f_g = 1 AND f_e = 1 AND f_h = 1 AND f_f = 1 AND t_b = 1 AND t_c = 1; + + SELECT * FROM d_to_a; +} {} + +faultsim_delete_and_reopen +do_execsql_test 2.0 { CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,d,e)) } +do_execsql_test 2.1 { CREATE TABLE t2(x) } +faultsim_save_and_close + +do_faultsim_test 3 -faults oom* -prep { + faultsim_restore_and_reopen + execsql { SELECT 1 FROM sqlite_master } +} -body { + execsql { SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=? AND e=? } +} -test { + faultsim_test_result {0 {}} +} + +finish_test + diff --git a/test/tkt-a8a0d2996a.test b/test/tkt-a8a0d2996a.test new file mode 100644 index 0000000..6b15e41 --- /dev/null +++ b/test/tkt-a8a0d2996a.test @@ -0,0 +1,93 @@ +# 2014-03-24 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Tests to verify that arithmetic operators do not change the type of +# input operands. Ticket [a8a0d2996a] +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix tkt-a8a0d2996a + +do_execsql_test 1.0 { + CREATE TABLE t(x,y); + INSERT INTO t VALUES('1','1'); + SELECT typeof(x), typeof(y) FROM t WHERE 1=x+0 AND y=='1'; +} {text text} +do_execsql_test 1.1 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x-0 AND y=='1'; +} {text text} +do_execsql_test 1.2 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x*1 AND y=='1'; +} {text text} +do_execsql_test 1.3 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x/1 AND y=='1'; +} {text text} +do_execsql_test 1.4 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x%4 AND y=='1'; +} {text text} + +do_execsql_test 2.0 { + UPDATE t SET x='1xyzzy'; + SELECT typeof(x), typeof(y) FROM t WHERE 1=x+0 AND y=='1'; +} {text text} +do_execsql_test 2.1 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x-0 AND y=='1'; +} {text text} +do_execsql_test 2.2 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x*1 AND y=='1'; +} {text text} +do_execsql_test 2.3 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x/1 AND y=='1'; +} {text text} +do_execsql_test 2.4 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x%4 AND y=='1'; +} {text text} + + +do_execsql_test 3.0 { + UPDATE t SET x='1.0'; + SELECT typeof(x), typeof(y) FROM t WHERE 1=x+0 AND y=='1'; +} {text text} +do_execsql_test 3.1 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x-0 AND y=='1'; +} {text text} +do_execsql_test 3.2 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x*1 AND y=='1'; +} {text text} +do_execsql_test 3.3 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x/1 AND y=='1'; +} {text text} +do_execsql_test 3.4 { + SELECT typeof(x), typeof(y) FROM t WHERE 1=x%4 AND y=='1'; +} {text text} + +do_execsql_test 4.0 { + SELECT 1+1.; +} {2.0} +do_execsql_test 4.1 { + SELECT '1.23e64'/'1.0000e+62'; +} {123.0} +do_execsql_test 4.2 { + SELECT '100x'+'-2y'; +} {98} +do_execsql_test 4.3 { + SELECT '100x'+'4.5y'; +} {104.5} +do_execsql_test 4.4 { + SELECT '-9223372036854775807x'-'1x'; +} {-9.22337203685478e+18} +do_execsql_test 4.5 { + SELECT '9223372036854775806x'+'1x'; +} {9.22337203685478e+18} +do_execsql_test 4.6 { + SELECT '1234x'/'10y'; +} {123.4} diff --git a/test/tkt-b1d3a2e531.test b/test/tkt-b1d3a2e531.test index 54534b6..745bbe8 100644 --- a/test/tkt-b1d3a2e531.test +++ b/test/tkt-b1d3a2e531.test @@ -98,7 +98,7 @@ do_catchsql_test 3.2 { DROP TABLE pp1; DROP TABLE cc1; COMMIT; -} {1 {foreign key constraint failed}} +} {1 {FOREIGN KEY constraint failed}} do_catchsql_test 3.3 { DROP TABLE cc2; COMMIT; diff --git a/test/tkt-b75a9ca6b0.test b/test/tkt-b75a9ca6b0.test new file mode 100644 index 0000000..0c81a53 --- /dev/null +++ b/test/tkt-b75a9ca6b0.test @@ -0,0 +1,77 @@ +# 2014-04-21 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# +# Test that ticket [b75a9ca6b0] has been fixed. +# +# Ticket [b75a9ca6b0] concerns queries that have both a GROUP BY +# and an ORDER BY. This code verifies that SQLite is able to +# optimize out the ORDER BY in some circumstances, but retains the +# ORDER BY when necessary. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix tkt-b75a9ca6b0 + +do_execsql_test 1 { + CREATE TABLE t1 (x, y); + INSERT INTO t1 VALUES (1, 3); + INSERT INTO t1 VALUES (2, 2); + INSERT INTO t1 VALUES (3, 1); +} + +do_execsql_test 1.1 { + CREATE INDEX i1 ON t1(x, y); +} + +set idxscan {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}} +set tblscan {0 0 0 {SCAN TABLE t1}} +set grpsort {0 0 0 {USE TEMP B-TREE FOR GROUP BY}} +set sort {0 0 0 {USE TEMP B-TREE FOR ORDER BY}} + +foreach {tn q res eqp} [subst -nocommands { + 1 "SELECT * FROM t1 GROUP BY x, y ORDER BY x,y" + {1 3 2 2 3 1} {$idxscan} + + 2 "SELECT * FROM t1 GROUP BY x, y ORDER BY x" + {1 3 2 2 3 1} {$idxscan $sort} + + 3 "SELECT * FROM t1 GROUP BY y, x ORDER BY y, x" + {3 1 2 2 1 3} {$idxscan $sort} + + 4 "SELECT * FROM t1 GROUP BY x ORDER BY x" + {1 3 2 2 3 1} {$idxscan} + + 5 "SELECT * FROM t1 GROUP BY y ORDER BY y" + {3 1 2 2 1 3} {$tblscan $grpsort} + + 6 "SELECT * FROM t1 GROUP BY y ORDER BY x" + {1 3 2 2 3 1} {$tblscan $grpsort $sort} + + 7 "SELECT * FROM t1 GROUP BY x, y ORDER BY x, y DESC" + {1 3 2 2 3 1} {$idxscan $sort} + + 8 "SELECT * FROM t1 GROUP BY x, y ORDER BY x DESC, y DESC" + {3 1 2 2 1 3} {$idxscan $sort} + + 9 "SELECT * FROM t1 GROUP BY x, y ORDER BY x ASC, y ASC" + {1 3 2 2 3 1} {$idxscan} + + 10 "SELECT * FROM t1 GROUP BY x, y ORDER BY x COLLATE nocase, y" + {1 3 2 2 3 1} {$idxscan $sort} + +}] { + do_execsql_test 1.$tn.1 $q $res + do_eqp_test 1.$tn.2 $q $eqp +} + + +finish_test diff --git a/test/tkt-c48d99d690.test b/test/tkt-c48d99d690.test index 9b40579..6d1b9db 100644 --- a/test/tkt-c48d99d690.test +++ b/test/tkt-c48d99d690.test @@ -23,4 +23,3 @@ do_test 1.1 { do_test 1.2 { execsql VACUUM } {} finish_test - diff --git a/test/tkt-cbd054fa6b.test b/test/tkt-cbd054fa6b.test index 51e0199..2951233 100644 --- a/test/tkt-cbd054fa6b.test +++ b/test/tkt-cbd054fa6b.test @@ -16,11 +16,26 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !stat3 { +ifcapable !stat4&&!stat3 { finish_test return } +proc s {blob} { + set ret "" + binary scan $blob c* bytes + foreach b $bytes { + set t [binary format c $b] + if {[string is print $t]} { + append ret $t + } else { + append ret . + } + } + return $ret +} +db function s s + do_test tkt-cbd05-1.1 { db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT UNIQUE NOT NULL); @@ -39,18 +54,30 @@ do_test tkt-cbd05-1.1 { } } {10} do_test tkt-cbd05-1.2 { - db eval { - ANALYZE; + db eval { ANALYZE; } + ifcapable stat4 { + db eval { + PRAGMA writable_schema = 1; + CREATE VIEW vvv AS + SELECT tbl,idx,neq,nlt,ndlt,test_extract(sample,0) AS sample + FROM sqlite_stat4; + PRAGMA writable_schema = 0; + } + } else { + db eval { + CREATE VIEW vvv AS + SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3; + } } } {} do_test tkt-cbd05-1.3 { execsql { - SELECT tbl,idx,group_concat(sample,' ') - FROM sqlite_stat3 + SELECT tbl,idx,group_concat(s(sample),' ') + FROM vvv WHERE idx = 't1_x' GROUP BY tbl,idx } -} {/t1 t1_x .[ ABCDEFGHI]{10}./} +} {t1 t1_x { A B C D E F G H I}} do_test tkt-cbd05-2.1 { db eval { @@ -77,11 +104,11 @@ do_test tkt-cbd05-2.2 { } {} do_test tkt-cbd05-2.3 { execsql { - SELECT tbl,idx,group_concat(sample,' ') - FROM sqlite_stat3 + SELECT tbl,idx,group_concat(s(sample),' ') + FROM vvv WHERE idx = 't1_x' GROUP BY tbl,idx } -} {/t1 t1_x .[ ABCDEFGHI]{10}./} +} {t1 t1_x { A B C D E F G H I}} finish_test diff --git a/test/tkt-d11f09d36e.test b/test/tkt-d11f09d36e.test index 7065770..ffd3d21 100644 --- a/test/tkt-d11f09d36e.test +++ b/test/tkt-d11f09d36e.test @@ -59,4 +59,3 @@ do_test tkt-d11f09d36e.5 { } {ok} finish_test - diff --git a/test/tkt-f3e5abed55.test b/test/tkt-f3e5abed55.test index b3f5d56..3c793d4 100644 --- a/test/tkt-f3e5abed55.test +++ b/test/tkt-f3e5abed55.test @@ -114,4 +114,3 @@ if {[permutation]!="inmemory_journal"} { finish_test - diff --git a/test/tkt-f67b41381a.test b/test/tkt-f67b41381a.test new file mode 100644 index 0000000..1ddec98 --- /dev/null +++ b/test/tkt-f67b41381a.test @@ -0,0 +1,53 @@ +# 2014 April 26 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# Test that ticket f67b41381a has been resolved. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix tkt-f67b41381a + +do_execsql_test 1.0 { + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(1); + ALTER TABLE t1 ADD COLUMN b DEFAULT 2; + CREATE TABLE t2(a, b); + INSERT INTO t2 SELECT * FROM t1; + SELECT * FROM t2; +} {1 2} + +db cache size 0 +foreach {tn tbls xfer} { + 1 { CREATE TABLE t1(a, b); CREATE TABLE t2(a, b) } 1 + 2 { CREATE TABLE t1(a, b DEFAULT 'x'); CREATE TABLE t2(a, b) } 0 + 3 { CREATE TABLE t1(a, b DEFAULT 'x'); CREATE TABLE t2(a, b DEFAULT 'x') } 1 + 4 { CREATE TABLE t1(a, b DEFAULT NULL); CREATE TABLE t2(a, b) } 0 + 5 { CREATE TABLE t1(a DEFAULT 2, b); CREATE TABLE t2(a DEFAULT 1, b) } 1 + 6 { CREATE TABLE t1(a DEFAULT 1, b); CREATE TABLE t2(a DEFAULT 1, b) } 1 + 7 { CREATE TABLE t1(a DEFAULT 1, b DEFAULT 1); + CREATE TABLE t2(a DEFAULT 3, b DEFAULT 1) } 1 + 8 { CREATE TABLE t1(a DEFAULT 1, b DEFAULT 1); + CREATE TABLE t2(a DEFAULT 3, b DEFAULT 3) } 0 + +} { + + execsql { DROP TABLE t1; DROP TABLE t2 } + execsql $tbls + + set res 1 + db eval { EXPLAIN INSERT INTO t1 SELECT * FROM t2 } { + if {$opcode == "Column"} { set res 0 } + } + + do_test 2.$tn [list set res] $xfer +} + +finish_test diff --git a/test/tkt-f973c7ac31.test b/test/tkt-f973c7ac31.test index 882e86a..4543090 100644 --- a/test/tkt-f973c7ac31.test +++ b/test/tkt-f973c7ac31.test @@ -84,4 +84,3 @@ foreach {tn sql} { finish_test - diff --git a/test/tkt1567.test b/test/tkt1567.test index 6c4548a..cb1a6be 100644 --- a/test/tkt1567.test +++ b/test/tkt1567.test @@ -40,7 +40,7 @@ do_test tkt1567-1.4 { catchsql { UPDATE t1 SET a = CASE WHEN rowid<90 THEN substr(a,1,10) ELSE '9999' END; } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test tkt1567-1.5 { execsql { COMMIT; @@ -48,4 +48,35 @@ do_test tkt1567-1.5 { } {} integrity_check tkt1567-1.6 +do_test tkt1567-2.1 { + execsql { + CREATE TABLE t2(a TEXT PRIMARY KEY, rowid INT) WITHOUT rowid; + } + set bigstr abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + for {set i 0} {$i<100} {incr i} { + set x [format %5d [expr $i*2]] + set sql "INSERT INTO t2 VALUES('$x-$bigstr', $i+1)" + execsql $sql + } +} {} +integrity_check tkt1567-2.2 + +do_test tkt1567-2.3 { + execsql { + BEGIN; + UPDATE t2 SET a = a||'x' WHERE rowid%2==0; + } +} {} +do_test tkt1567-2.4 { + catchsql { + UPDATE t2 SET a = CASE WHEN rowid<90 THEN substr(a,1,10) ELSE '9999' END; + } +} {1 {UNIQUE constraint failed: t2.a}} +do_test tkt1567-2.5 { + execsql { + COMMIT; + } +} {} +integrity_check tkt1567-2.6 + finish_test diff --git a/test/tkt2822.test b/test/tkt2822.test index d3512d3..d0b1633 100644 --- a/test/tkt2822.test +++ b/test/tkt2822.test @@ -208,15 +208,12 @@ do_test tkt2822-5.4 { # In "ORDER BY +b" the term is now an expression rather than # a label. It therefore matches by rule (3) instead of rule (2). -# -# 2013-04-13: This is busted. Changed to conform to PostgreSQL and -# MySQL and Oracle behavior. # do_test tkt2822-5.5 { execsql { SELECT a AS b FROM t3 ORDER BY +b; } -} {1 9} +} {9 1} # Tests for rule 2 in compound queries # diff --git a/test/tkt3442.test b/test/tkt3442.test index ae03949..ee9169c 100644 --- a/test/tkt3442.test +++ b/test/tkt3442.test @@ -49,10 +49,10 @@ proc EQP {sql} { ifcapable explain { do_test tkt3442-1.2 { EQP { SELECT node FROM listhash WHERE id='5000' LIMIT 1; } - } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?) (~1 rows)}} + } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?)}} do_test tkt3442-1.3 { EQP { SELECT node FROM listhash WHERE id="5000" LIMIT 1; } - } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?) (~1 rows)}} + } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?)}} } @@ -61,7 +61,7 @@ ifcapable explain { ifcapable explain { do_test tkt3442-1.4 { EQP { SELECT node FROM listhash WHERE id=5000 LIMIT 1; } - } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?) (~1 rows)}} + } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?)}} } do_test tkt3442-1.5 { catchsql { diff --git a/test/tkt35xx.test b/test/tkt35xx.test index f9d10c3..3b911c1 100644 --- a/test/tkt35xx.test +++ b/test/tkt35xx.test @@ -74,7 +74,7 @@ do_test tkt35xx-1.2.2 { DROP TABLE t5; INSERT INTO t3(a, b) SELECT c, d FROM t4; } -} {1 {PRIMARY KEY must be unique}} +} {1 {UNIQUE constraint failed: t3.a}} do_test tkt35xx-1.2.3 { # Show that the transaction has not been rolled back. catchsql BEGIN diff --git a/test/tkt3918.test b/test/tkt3918.test index c46ad8f..e20ee15 100644 --- a/test/tkt3918.test +++ b/test/tkt3918.test @@ -57,4 +57,3 @@ do_test tkt3918.5 { } {} finish_test - diff --git a/test/tkt3929.test b/test/tkt3929.test index 3ed4d28..db02bb8 100644 --- a/test/tkt3929.test +++ b/test/tkt3929.test @@ -50,4 +50,3 @@ do_test tkt3930-1.2 { integrity_check tkt3930-1.3 finish_test - diff --git a/test/tpch01.test b/test/tpch01.test new file mode 100644 index 0000000..ce48f8e --- /dev/null +++ b/test/tpch01.test @@ -0,0 +1,192 @@ +# 2013-09-05 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# TPC-H test queries. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix tpch01 + +do_execsql_test tpch01-1.0 { + CREATE TABLE NATION ( N_NATIONKEY INTEGER NOT NULL, + N_NAME CHAR(25) NOT NULL, + N_REGIONKEY INTEGER NOT NULL, + N_COMMENT VARCHAR(152)); + CREATE TABLE REGION ( R_REGIONKEY INTEGER NOT NULL, + R_NAME CHAR(25) NOT NULL, + R_COMMENT VARCHAR(152)); + CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL, + P_NAME VARCHAR(55) NOT NULL, + P_MFGR CHAR(25) NOT NULL, + P_BRAND CHAR(10) NOT NULL, + P_TYPE VARCHAR(25) NOT NULL, + P_SIZE INTEGER NOT NULL, + P_CONTAINER CHAR(10) NOT NULL, + P_RETAILPRICE DECIMAL(15,2) NOT NULL, + P_COMMENT VARCHAR(23) NOT NULL ); + CREATE TABLE SUPPLIER ( S_SUPPKEY INTEGER NOT NULL, + S_NAME CHAR(25) NOT NULL, + S_ADDRESS VARCHAR(40) NOT NULL, + S_NATIONKEY INTEGER NOT NULL, + S_PHONE CHAR(15) NOT NULL, + S_ACCTBAL DECIMAL(15,2) NOT NULL, + S_COMMENT VARCHAR(101) NOT NULL); + CREATE TABLE PARTSUPP ( PS_PARTKEY INTEGER NOT NULL, + PS_SUPPKEY INTEGER NOT NULL, + PS_AVAILQTY INTEGER NOT NULL, + PS_SUPPLYCOST DECIMAL(15,2) NOT NULL, + PS_COMMENT VARCHAR(199) NOT NULL ); + CREATE TABLE CUSTOMER ( C_CUSTKEY INTEGER NOT NULL, + C_NAME VARCHAR(25) NOT NULL, + C_ADDRESS VARCHAR(40) NOT NULL, + C_NATIONKEY INTEGER NOT NULL, + C_PHONE CHAR(15) NOT NULL, + C_ACCTBAL DECIMAL(15,2) NOT NULL, + C_MKTSEGMENT CHAR(10) NOT NULL, + C_COMMENT VARCHAR(117) NOT NULL); + CREATE TABLE ORDERS ( O_ORDERKEY INTEGER NOT NULL, + O_CUSTKEY INTEGER NOT NULL, + O_ORDERSTATUS CHAR(1) NOT NULL, + O_TOTALPRICE DECIMAL(15,2) NOT NULL, + O_ORDERDATE DATE NOT NULL, + O_ORDERPRIORITY CHAR(15) NOT NULL, + O_CLERK CHAR(15) NOT NULL, + O_SHIPPRIORITY INTEGER NOT NULL, + O_COMMENT VARCHAR(79) NOT NULL); + CREATE TABLE LINEITEM ( L_ORDERKEY INTEGER NOT NULL, + L_PARTKEY INTEGER NOT NULL, + L_SUPPKEY INTEGER NOT NULL, + L_LINENUMBER INTEGER NOT NULL, + L_QUANTITY DECIMAL(15,2) NOT NULL, + L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL, + L_DISCOUNT DECIMAL(15,2) NOT NULL, + L_TAX DECIMAL(15,2) NOT NULL, + L_RETURNFLAG CHAR(1) NOT NULL, + L_LINESTATUS CHAR(1) NOT NULL, + L_SHIPDATE DATE NOT NULL, + L_COMMITDATE DATE NOT NULL, + L_RECEIPTDATE DATE NOT NULL, + L_SHIPINSTRUCT CHAR(25) NOT NULL, + L_SHIPMODE CHAR(10) NOT NULL, + L_COMMENT VARCHAR(44) NOT NULL); + CREATE INDEX npki on nation(N_NATIONKEY); + CREATE INDEX rpki on region(R_REGIONKEY); + CREATE INDEX ppki on part(P_PARTKEY); + CREATE INDEX spki on supplier(S_SUPPKEY); + CREATE INDEX pspki on partsupp(PS_PARTKEY, PS_SUPPKEY); + CREATE INDEX cpki on customer(C_CUSTKEY); + CREATE INDEX opki on orders(O_ORDERKEY); + CREATE INDEX lpki on lineitem(L_ORDERKEY, L_LINENUMBER); + CREATE INDEX nrki on nation(n_regionkey); + CREATE INDEX snki on supplier(s_nationkey); + CREATE INDEX cnki on customer(c_nationkey); + CREATE INDEX ocki on orders(O_CUSTKEY); + CREATE INDEX odi on orders(O_ORDERDATE); + CREATE INDEX lpki2 on lineitem(L_PARTKEY); + CREATE INDEX lski on lineitem(L_SUPPKEY); + CREATE INDEX lsdi on lineitem(L_SHIPDATE); + CREATE INDEX lcdi on lineitem(L_COMMITDATE); + CREATE INDEX lrdi on lineitem(L_RECEIPTDATE); + CREATE INDEX bootleg_nni on nation(N_NAME); + CREATE INDEX bootleg_psi on part(p_size); + CREATE INDEX bootleg_pti on part(p_type); + ANALYZE sqlite_master; + INSERT INTO sqlite_stat1 VALUES('LINEITEM','lrdi','600572 236'); + INSERT INTO sqlite_stat1 VALUES('LINEITEM','lcdi','600572 244'); + INSERT INTO sqlite_stat1 VALUES('LINEITEM','lsdi','600572 238'); + INSERT INTO sqlite_stat1 VALUES('LINEITEM','lski','600572 601'); + INSERT INTO sqlite_stat1 VALUES('LINEITEM','lpki2','600572 31'); + INSERT INTO sqlite_stat1 VALUES('LINEITEM','lpki','600572 5 1'); + INSERT INTO sqlite_stat1 VALUES('ORDERS','odi','150000 63'); + INSERT INTO sqlite_stat1 VALUES('ORDERS','ocki','150000 15'); + INSERT INTO sqlite_stat1 VALUES('ORDERS','opki','150000 1'); + INSERT INTO sqlite_stat1 VALUES('CUSTOMER','cnki','15000 600'); + INSERT INTO sqlite_stat1 VALUES('CUSTOMER','cpki','15000 1'); + INSERT INTO sqlite_stat1 VALUES('PARTSUPP','pspki','80000 4 1'); + INSERT INTO sqlite_stat1 VALUES('SUPPLIER','snki','1000 40'); + INSERT INTO sqlite_stat1 VALUES('SUPPLIER','spki','1000 1'); + INSERT INTO sqlite_stat1 VALUES('PART','bootleg_pti','20000 134'); + INSERT INTO sqlite_stat1 VALUES('PART','bootleg_psi','20000 400'); + INSERT INTO sqlite_stat1 VALUES('PART','ppki','20000 1'); + INSERT INTO sqlite_stat1 VALUES('REGION','rpki','5 1'); + INSERT INTO sqlite_stat1 VALUES('NATION','bootleg_nni','25 1'); + INSERT INTO sqlite_stat1 VALUES('NATION','nrki','25 5'); + INSERT INTO sqlite_stat1 VALUES('NATION','npki','25 1'); + ANALYZE sqlite_master; +} {} + +do_test tpch01-1.1 { + unset -nocomplain ::eqpres + set ::eqpres [db eval {EXPLAIN QUERY PLAN + select + o_year, + sum(case + when nation = 'EGYPT' then volume + else 0 + end) / sum(volume) as mkt_share + from + ( + select + strftime('%Y', o_orderdate) as o_year, + l_extendedprice * (1 - l_discount) as volume, + n2.n_name as nation + from + part, + supplier, + lineitem, + orders, + customer, + nation n1, + nation n2, + region + where + p_partkey = l_partkey + and s_suppkey = l_suppkey + and l_orderkey = o_orderkey + and o_custkey = c_custkey + and c_nationkey = n1.n_nationkey + and n1.n_regionkey = r_regionkey + and r_name = 'MIDDLE EAST' + and s_nationkey = n2.n_nationkey + and o_orderdate between '1995-01-01' and '1996-12-31' + and p_type = 'LARGE PLATED STEEL' + ) as all_nations + group by + o_year + order by + o_year;}] + set ::eqpres +} {/0 0 0 {SEARCH TABLE part USING INDEX bootleg_pti .P_TYPE=..} 0 1 2 {SEARCH TABLE lineitem USING INDEX lpki2 .L_PARTKEY=..}.*/} +do_test tpch01-1.1b { + set ::eqpres +} {/.* customer .* nation AS n1 .*/} +do_test tpch01-1.1c { + set ::eqpres +} {/.* supplier .* nation AS n2 .*/} + +do_eqp_test tpch01-1.2 { +select + c_custkey, c_name, sum(l_extendedprice * (1 - l_discount)) as revenue, + c_acctbal, n_name, c_address, c_phone, c_comment +from + customer, orders, lineitem, nation +where + c_custkey = o_custkey and l_orderkey = o_orderkey + and o_orderdate >= '1994-08-01' and o_orderdate < date('1994-08-01', '+3 month') + and l_returnflag = 'R' and c_nationkey = n_nationkey +group by + c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment +order by + revenue desc; +} {0 0 1 {SEARCH TABLE orders USING INDEX odi (O_ORDERDATE>? AND O_ORDERDATE<?)} 0 1 0 {SEARCH TABLE customer USING INDEX cpki (C_CUSTKEY=?)} 0 2 3 {SEARCH TABLE nation USING INDEX npki (N_NATIONKEY=?)} 0 3 2 {SEARCH TABLE lineitem USING INDEX lpki (L_ORDERKEY=?)} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} + +finish_test diff --git a/test/trace2.test b/test/trace2.test index 2f7ae7d..562c70c 100644 --- a/test/trace2.test +++ b/test/trace2.test @@ -128,6 +128,7 @@ ifcapable fts3 { INSERT INTO x1 VALUES('North northwest wind between 8 and 14 mph'); } { "INSERT INTO x1 VALUES('North northwest wind between 8 and 14 mph');" + "-- DELETE FROM 'main'.'x1_segdir' WHERE level = ?" "-- INSERT INTO 'main'.'x1_content' VALUES(?,(?))" "-- REPLACE INTO 'main'.'x1_docsize' VALUES(?,?)" "-- SELECT value FROM 'main'.'x1_stat' WHERE id=?" @@ -135,6 +136,7 @@ ifcapable fts3 { "-- SELECT (SELECT max(idx) FROM 'main'.'x1_segdir' WHERE level = ?) + 1" "-- SELECT coalesce((SELECT max(blockid) FROM 'main'.'x1_segments') + 1, 1)" "-- REPLACE INTO 'main'.'x1_segdir' VALUES(?,?,?,?,?,?)" + "-- SELECT level, idx, end_block FROM 'main'.'x1_segdir' WHERE level BETWEEN ? AND ? ORDER BY level DESC, idx ASC" } do_trace_test 2.3 { diff --git a/test/trans2.test b/test/trans2.test index cfd3e67..36a2f99 100644 --- a/test/trans2.test +++ b/test/trans2.test @@ -161,7 +161,7 @@ for {set i 2} {$i<=30} {incr i} { z = CASE WHEN id<$max_rowid THEN zeroblob((random()&65535)%5000 + 1000) END; } - } {1 {t1.z may not be NULL}} + } {1 {NOT NULL constraint failed: t1.z}} do_test trans2-$i.11 { db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id} } $newres @@ -185,7 +185,7 @@ for {set i 2} {$i<=30} {incr i} { z = CASE WHEN id<$max1 THEN zeroblob((random()&65535)%5000 + 1000) END; } - } {1 {t1.z may not be NULL}} + } {1 {NOT NULL constraint failed: t1.z}} do_test trans2-$i.31 { db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id} } $origres diff --git a/test/transitive1.test b/test/transitive1.test index ff81af6..200dc61 100644 --- a/test/transitive1.test +++ b/test/transitive1.test @@ -47,4 +47,238 @@ do_execsql_test transitive1-220 { SELECT * FROM t2 WHERE a=b AND c=b AND c<=20 ORDER BY +a; } {20 20 20 100 100 100} +# Test cases for ticket [[d805526eae253103] 2013-07-08 +# "Incorrect join result or assertion fault due to transitive constraints" +# +do_execsql_test transitive1-300 { + CREATE TABLE t301(w INTEGER PRIMARY KEY, x); + CREATE TABLE t302(y INTEGER UNIQUE, z); + INSERT INTO t301 VALUES(1,2),(3,4),(5,6); + INSERT INTO t302 VALUES(1,3),(3,6),(5,7); + SELECT * + FROM t301 CROSS JOIN t302 + WHERE w=y AND y IS NOT NULL + ORDER BY +w; +} {1 2 1 3 3 4 3 6 5 6 5 7} +do_execsql_test transitive1-301 { + SELECT * + FROM t301 CROSS JOIN t302 + WHERE w=y AND y IS NOT NULL + ORDER BY w; +} {1 2 1 3 3 4 3 6 5 6 5 7} +do_execsql_test transitive1-310 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y>1 + ORDER BY +w +} {3 4 3 6 5 6 5 7} +do_execsql_test transitive1-311 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y>1 + ORDER BY w +} {3 4 3 6 5 6 5 7} +do_execsql_test transitive1-312 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y>1 + ORDER BY w DESC +} {5 6 5 7 3 4 3 6} +do_execsql_test transitive1-320 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y BETWEEN 2 AND 4; +} {3 4 3 6} +do_execsql_test transitive1-331 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y BETWEEN 1 AND 4 + ORDER BY w; +} {1 2 1 3 3 4 3 6} +do_execsql_test transitive1-332 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y BETWEEN 1 AND 4 + ORDER BY w DESC; +} {3 4 3 6 1 2 1 3} + +# Ticket [c620261b5b5dc] circa 2013-10-28. +# Make sureconstraints are not used with LEFT JOINs. +# +# The next case is from the ticket report. It outputs no rows in 3.8.1 +# prior to the bug-fix. +# +do_execsql_test transitive1-400 { + CREATE TABLE t401(a); + CREATE TABLE t402(b); + CREATE TABLE t403(c INTEGER PRIMARY KEY); + INSERT INTO t401 VALUES(1); + INSERT INTO t403 VALUES(1); + SELECT '1-row' FROM t401 LEFT JOIN t402 ON b=a JOIN t403 ON c=a; +} {1-row} + +# The following is a script distilled from the XBMC project where the +# bug was originally encountered. The correct answer is a single row +# of output. Before the bug was fixed, zero rows were generated. +# +do_execsql_test transitive1-410 { + CREATE TABLE bookmark ( idBookmark integer primary key, idFile integer, timeInSeconds double, totalTimeInSeconds double, thumbNailImage text, player text, playerState text, type integer); + CREATE TABLE path ( idPath integer primary key, strPath text, strContent text, strScraper text, strHash text, scanRecursive integer, useFolderNames bool, strSettings text, noUpdate bool, exclude bool, dateAdded text); + INSERT INTO "path" VALUES(1,'/tmp/tvshows/','tvshows','metadata.tvdb.com','989B1CE5680A14F5F86123F751169B49',0,0,'<settings><setting id="absolutenumber" value="false" /><setting id="dvdorder" value="false" /><setting id="fanart" value="true" /><setting id="language" value="en" /></settings>',0,0,NULL); + INSERT INTO "path" VALUES(2,'/tmp/tvshows/The.Big.Bang.Theory/','','','85E1DAAB2F5FF6EAE8AEDF1B5C882D1E',NULL,NULL,NULL,NULL,NULL,'2013-10-23 18:58:43'); + CREATE TABLE files ( idFile integer primary key, idPath integer, strFilename text, playCount integer, lastPlayed text, dateAdded text); + INSERT INTO "files" VALUES(1,2,'The.Big.Bang.Theory.S01E01.WEB-DL.AAC2.0.H264.mkv',NULL,NULL,'2013-10-23 18:57:36'); + CREATE TABLE tvshow ( idShow integer primary key,c00 text,c01 text,c02 text,c03 text,c04 text,c05 text,c06 text,c07 text,c08 text,c09 text,c10 text,c11 text,c12 text,c13 text,c14 text,c15 text,c16 text,c17 text,c18 text,c19 text,c20 text,c21 text,c22 text,c23 text); + INSERT INTO "tvshow" VALUES(1,'The Big Bang Theory','Leonard Hofstadter and Sheldon Cooper are brilliant physicists, the kind of "beautiful minds" that understand how the universe works. But none of that genius helps them interact with people, especially women. All this begins to change when a free-spirited beauty named Penny moves in next door. Sheldon, Leonard''s roommate, is quite content spending his nights playing Klingon Boggle with their socially dysfunctional friends, fellow CalTech scientists Howard Wolowitz and Raj Koothrappali. However, Leonard sees in Penny a whole new universe of possibilities... including love.','','','9.200000','2007-09-24','<thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g13.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g23.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g18.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g17.jpg</thumb><thumb aspect="banner">http:// + thetvdb.com/banners/graphical/80379-g6.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g5.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g2.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g11.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g12.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g19.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g3.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g4.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g15.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g22.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g7.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g10.jpg</thumb><thumb + aspect="banner">http://thetvdb.com/banners/graphical/80379-g24.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g8.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g9.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g14.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g16.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/graphical/80379-g21.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/text/80379-4.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/text/80379-2.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/text/80379-3.jpg</thumb><thumb aspect="banner">http://thetvdb.com/banners/text/80379-5.jpg</thumb><thumb aspect="poster" type="season" season="6">http://thetvdb.com/banners/seasons/80379-6-8.jpg</thumb><thumb aspect="poster" type="season" season="0">http://thetvdb.com/banners/seasons/80379-0-4.jpg</thumb><thumb aspect="poster" type="season" + season="1">http://thetvdb.com/banners/seasons/80379-1-12.jpg</thumb><thumb aspect="poster" type="season" season="3">http://thetvdb.com/banners/seasons/80379-3-9.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-11.jpg</thumb><thumb aspect="poster" type="season" season="5">http://thetvdb.com/banners/seasons/80379-5-9.jpg</thumb><thumb aspect="poster" type="season" season="4">http://thetvdb.com/banners/seasons/80379-4-8.jpg</thumb><thumb aspect="poster" type="season" season="7">http://thetvdb.com/banners/seasons/80379-7-3.jpg</thumb><thumb aspect="poster" type="season" season="3">http://thetvdb.com/banners/seasons/80379-3-4.jpg</thumb><thumb aspect="poster" type="season" season="4">http://thetvdb.com/banners/seasons/80379-4-5.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-9.jpg</thumb><thumb aspect="poster" type="season" season="0">http://thetvdb.com/banners/seasons/80379-0-2.jpg</thumb><thumb aspect=" + poster" type="season" season="6">http://thetvdb.com/banners/seasons/80379-6-6.jpg</thumb><thumb aspect="poster" type="season" season="4">http://thetvdb.com/banners/seasons/80379-4-4.jpg</thumb><thumb aspect="poster" type="season" season="6">http://thetvdb.com/banners/seasons/80379-6-2.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/seasons/80379-1-9.jpg</thumb><thumb aspect="poster" type="season" season="6">http://thetvdb.com/banners/seasons/80379-6-4.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/seasons/80379-1.jpg</thumb><thumb aspect="poster" type="season" season="3">http://thetvdb.com/banners/seasons/80379-3.jpg</thumb><thumb aspect="poster" type="season" season="4">http://thetvdb.com/banners/seasons/80379-4-2.jpg</thumb><thumb aspect="poster" type="season" season="5">http://thetvdb.com/banners/seasons/80379-5-7.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-10.jpg</ + thumb><thumb aspect="poster" type="season" season="6">http://thetvdb.com/banners/seasons/80379-6-5.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/seasons/80379-1-5.jpg</thumb><thumb aspect="poster" type="season" season="5">http://thetvdb.com/banners/seasons/80379-5-4.jpg</thumb><thumb aspect="poster" type="season" season="4">http://thetvdb.com/banners/seasons/80379-4.jpg</thumb><thumb aspect="poster" type="season" season="6">http://thetvdb.com/banners/seasons/80379-6-3.jpg</thumb><thumb aspect="poster" type="season" season="5">http://thetvdb.com/banners/seasons/80379-5.jpg</thumb><thumb aspect="poster" type="season" season="3">http://thetvdb.com/banners/seasons/80379-3-6.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2.jpg</thumb><thumb aspect="poster" type="season" season="7">http://thetvdb.com/banners/seasons/80379-7.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/seasons/80379- + 1-7.jpg</thumb><thumb aspect="poster" type="season" season="5">http://thetvdb.com/banners/seasons/80379-5-2.jpg</thumb><thumb aspect="poster" type="season" season="5">http://thetvdb.com/banners/seasons/80379-5-3.jpg</thumb><thumb aspect="poster" type="season" season="7">http://thetvdb.com/banners/seasons/80379-7-2.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/seasons/80379-1-2.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-5.jpg</thumb><thumb aspect="poster" type="season" season="4">http://thetvdb.com/banners/seasons/80379-4-3.jpg</thumb><thumb aspect="poster" type="season" season="5">http://thetvdb.com/banners/seasons/80379-5-5.jpg</thumb><thumb aspect="poster" type="season" season="0">http://thetvdb.com/banners/seasons/80379-0.jpg</thumb><thumb aspect="poster" type="season" season="3">http://thetvdb.com/banners/seasons/80379-3-5.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/ + seasons/80379-1-6.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-3.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-8.jpg</thumb><thumb aspect="poster" type="season" season="6">http://thetvdb.com/banners/seasons/80379-6-7.jpg</thumb><thumb aspect="poster" type="season" season="5">http://thetvdb.com/banners/seasons/80379-5-8.jpg</thumb><thumb aspect="poster" type="season" season="4">http://thetvdb.com/banners/seasons/80379-4-7.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-6.jpg</thumb><thumb aspect="poster" type="season" season="3">http://thetvdb.com/banners/seasons/80379-3-8.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/seasons/80379-1-11.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/seasons/80379-1-10.jpg</thumb><thumb aspect="poster" type="season" season="1">http:// + thetvdb.com/banners/seasons/80379-1-8.jpg</thumb><thumb aspect="poster" type="season" season="3">http://thetvdb.com/banners/seasons/80379-3-7.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-4.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/seasons/80379-1-3.jpg</thumb><thumb aspect="poster" type="season" season="1">http://thetvdb.com/banners/seasons/80379-1-4.jpg</thumb><thumb aspect="poster" type="season" season="3">http://thetvdb.com/banners/seasons/80379-3-3.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-7.jpg</thumb><thumb aspect="poster" type="season" season="6">http://thetvdb.com/banners/seasons/80379-6.jpg</thumb><thumb aspect="poster" type="season" season="2">http://thetvdb.com/banners/seasons/80379-2-2.jpg</thumb><thumb aspect="poster" type="season" season="5">http://thetvdb.com/banners/seasons/80379-5-6.jpg</thumb><thumb aspect="poster" type="season" + season="3">http://thetvdb.com/banners/seasons/80379-3-2.jpg</thumb><thumb aspect="poster" type="season" season="4">http://thetvdb.com/banners/seasons/80379-4-6.jpg</thumb><thumb aspect="banner" type="season" season="5">http://thetvdb.com/banners/seasonswide/80379-5.jpg</thumb><thumb aspect="banner" type="season" season="3">http://thetvdb.com/banners/seasonswide/80379-3-2.jpg</thumb><thumb aspect="banner" type="season" season="1">http://thetvdb.com/banners/seasonswide/80379-1-2.jpg</thumb><thumb aspect="banner" type="season" season="2">http://thetvdb.com/banners/seasonswide/80379-2-2.jpg</thumb><thumb aspect="banner" type="season" season="4">http://thetvdb.com/banners/seasonswide/80379-4-2.jpg</thumb><thumb aspect="banner" type="season" season="0">http://thetvdb.com/banners/seasonswide/80379-0.jpg</thumb><thumb aspect="banner" type="season" season="0">http://thetvdb.com/banners/seasonswide/80379-0-2.jpg</thumb><thumb aspect="banner" type="season" season="1">http://thetvdb.com/banners/seasonswide/80379-1.jpg</ + thumb><thumb aspect="banner" type="season" season="2">http://thetvdb.com/banners/seasonswide/80379-2.jpg</thumb><thumb aspect="banner" type="season" season="4">http://thetvdb.com/banners/seasonswide/80379-4.jpg</thumb><thumb aspect="banner" type="season" season="3">http://thetvdb.com/banners/seasonswide/80379-3.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-22.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-18.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-13.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-10.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-16.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-1.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-9.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-2.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-19.jpg</ + thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-8.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-4.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-20.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-23.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-7.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-3.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-12.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-11.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-15.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-21.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-14.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-17.jpg</thumb><thumb aspect="poster">http://thetvdb.com/banners/posters/80379-6.jpg</thumb><thumb + aspect="poster">http://thetvdb.com/banners/posters/80379-5.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-22.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-18.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-13.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-10.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-16.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-1.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-9.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-2.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-19.jpg</thumb><thumb aspect=" + poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-8.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-4.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-20.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-23.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-7.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-3.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-12.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-11.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-15.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-21.jpg</ + thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-14.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-17.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-6.jpg</thumb><thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/posters/80379-5.jpg</thumb>','','Comedy','','<episodeguide><url cache="80379-en.xml">http://thetvdb.com/api/1D62F2F90030C444/series/80379/all/en.zip</url></episodeguide>','<fanart url="http://thetvdb.com/banners/"><thumb dim="1920x1080" colors="|192,185,169|19,20,25|57,70,89|" preview="_cache/fanart/original/80379-2.jpg">fanart/original/80379-2.jpg</thumb><thumb dim="1920x1080" colors="|94,28,16|194,18,38|0,0,8|" preview="_cache/fanart/original/80379-34.jpg">fanart/original/80379-34.jpg</thumb><thumb dim="1280x720" colors="|254,157,210|11,12,7|191,152,111|" preview="_cache/fanart/original/80379-4.jpg">fanart/original/80379- + 4.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-42.jpg">fanart/original/80379-42.jpg</thumb><thumb dim="1920x1080" colors="|236,187,155|136,136,128|254,254,252|" preview="_cache/fanart/original/80379-37.jpg">fanart/original/80379-37.jpg</thumb><thumb dim="1920x1080" colors="|112,102,152|116,109,116|235,152,146|" preview="_cache/fanart/original/80379-14.jpg">fanart/original/80379-14.jpg</thumb><thumb dim="1920x1080" colors="|150,158,161|174,75,121|150,98,58|" preview="_cache/fanart/original/80379-16.jpg">fanart/original/80379-16.jpg</thumb><thumb dim="1280x720" colors="|224,200,176|11,1,28|164,96,0|" preview="_cache/fanart/original/80379-1.jpg">fanart/original/80379-1.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-35.jpg">fanart/original/80379-35.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-40.jpg">fanart/original/80379-40.jpg</thumb><thumb dim="1920x1080" colors="|255,255,255|30,19,13|155,112,70|" + preview="_cache/fanart/original/80379-31.jpg">fanart/original/80379-31.jpg</thumb><thumb dim="1920x1080" colors="|241,195,172|84,54,106|254,221,206|" preview="_cache/fanart/original/80379-29.jpg">fanart/original/80379-29.jpg</thumb><thumb dim="1280x720" colors="|197,167,175|219,29,39|244,208,192|" preview="_cache/fanart/original/80379-11.jpg">fanart/original/80379-11.jpg</thumb><thumb dim="1280x720" colors="|195,129,97|244,192,168|219,148,118|" preview="_cache/fanart/original/80379-24.jpg">fanart/original/80379-24.jpg</thumb><thumb dim="1920x1080" colors="|14,10,11|255,255,255|175,167,164|" preview="_cache/fanart/original/80379-30.jpg">fanart/original/80379-30.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-19.jpg">fanart/original/80379-19.jpg</thumb><thumb dim="1920x1080" colors="|246,199,69|98,55,38|161,127,82|" preview="_cache/fanart/original/80379-9.jpg">fanart/original/80379-9.jpg</thumb><thumb dim="1280x720" colors="|129,22,14|48,50,39|223,182,64|" preview="_cache/ + fanart/original/80379-13.jpg">fanart/original/80379-13.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-45.jpg">fanart/original/80379-45.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-33.jpg">fanart/original/80379-33.jpg</thumb><thumb dim="1280x720" colors="|103,77,60|224,180,153|129,100,84|" preview="_cache/fanart/original/80379-10.jpg">fanart/original/80379-10.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-23.jpg">fanart/original/80379-23.jpg</thumb><thumb dim="1280x720" colors="|219,29,39|0,4,10|88,117,135|" preview="_cache/fanart/original/80379-12.jpg">fanart/original/80379-12.jpg</thumb><thumb dim="1920x1080" colors="|226,209,165|51,18,9|89,54,24|" preview="_cache/fanart/original/80379-5.jpg">fanart/original/80379-5.jpg</thumb><thumb dim="1280x720" colors="" preview="_cache/fanart/original/80379-26.jpg">fanart/original/80379-26.jpg</thumb><thumb dim="1280x720" colors="|249,251,229|126,47,53|251,226, + 107|" preview="_cache/fanart/original/80379-27.jpg">fanart/original/80379-27.jpg</thumb><thumb dim="1920x1080" colors="|233,218,65|30,27,46|173,53,18|" preview="_cache/fanart/original/80379-32.jpg">fanart/original/80379-32.jpg</thumb><thumb dim="1280x720" colors="|248,248,248|64,54,78|188,193,196|" preview="_cache/fanart/original/80379-3.jpg">fanart/original/80379-3.jpg</thumb><thumb dim="1280x720" colors="" preview="_cache/fanart/original/80379-25.jpg">fanart/original/80379-25.jpg</thumb><thumb dim="1280x720" colors="|159,150,133|59,39,32|168,147,104|" preview="_cache/fanart/original/80379-7.jpg">fanart/original/80379-7.jpg</thumb><thumb dim="1920x1080" colors="|221,191,157|11,7,6|237,146,102|" preview="_cache/fanart/original/80379-21.jpg">fanart/original/80379-21.jpg</thumb><thumb dim="1280x720" colors="" preview="_cache/fanart/original/80379-28.jpg">fanart/original/80379-28.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-36.jpg">fanart/original/80379-36.jpg</thumb><thumb + dim="1920x1080" colors="|253,237,186|33,25,22|245,144,38|" preview="_cache/fanart/original/80379-38.jpg">fanart/original/80379-38.jpg</thumb><thumb dim="1920x1080" colors="|174,111,68|243,115,50|252,226,45|" preview="_cache/fanart/original/80379-20.jpg">fanart/original/80379-20.jpg</thumb><thumb dim="1920x1080" colors="|63,56,123|87,59,47|63,56,123|" preview="_cache/fanart/original/80379-17.jpg">fanart/original/80379-17.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-43.jpg">fanart/original/80379-43.jpg</thumb><thumb dim="1280x720" colors="|69,68,161|142,118,142|222,191,137|" preview="_cache/fanart/original/80379-22.jpg">fanart/original/80379-22.jpg</thumb><thumb dim="1280x720" colors="|1,108,206|242,209,192|250,197,163|" preview="_cache/fanart/original/80379-15.jpg">fanart/original/80379-15.jpg</thumb><thumb dim="1280x720" colors="|239,229,237|0,0,0|167,136,115|" preview="_cache/fanart/original/80379-18.jpg">fanart/original/80379-18.jpg</thumb><thumb dim="1280x720" colors="" + preview="_cache/fanart/original/80379-6.jpg">fanart/original/80379-6.jpg</thumb><thumb dim="1280x720" colors="" preview="_cache/fanart/original/80379-8.jpg">fanart/original/80379-8.jpg</thumb><thumb dim="1280x720" colors="" preview="_cache/fanart/original/80379-41.jpg">fanart/original/80379-41.jpg</thumb><thumb dim="1920x1080" colors="" preview="_cache/fanart/original/80379-44.jpg">fanart/original/80379-44.jpg</thumb><thumb dim="1280x720" colors="" preview="_cache/fanart/original/80379-39.jpg">fanart/original/80379-39.jpg</thumb></fanart>','80379','TV-PG','CBS','','/tmp/tvshows/The.Big.Bang.Theory/','1',NULL,NULL,NULL,NULL,NULL,NULL); + CREATE TABLE episode ( idEpisode integer primary key, idFile integer,c00 text,c01 text,c02 text,c03 text,c04 text,c05 text,c06 text,c07 text,c08 text,c09 text,c10 text,c11 text,c12 varchar(24),c13 varchar(24),c14 text,c15 text,c16 text,c17 varchar(24),c18 text,c19 text,c20 text,c21 text,c22 text,c23 text, idShow integer); + INSERT INTO "episode" VALUES(1,1,'Pilot','Brilliant physicist roommates Leonard and Sheldon meet their new neighbor Penny, who begins showing them that as much as they know about science, they know little about actual living.','','7.700000','Chuck Lorre / Bill Prady','2007-09-24','<thumb>http://thetvdb.com/banners/episodes/80379/332484.jpg</thumb>','',NULL,'1800','James Burrows','','1','1','','-1','-1','-1','/tmp/tvshows/The.Big.Bang.Theory/The.Big.Bang.Theory.S01E01.WEB-DL.AAC2.0.H264.mkv','2','332484',NULL,NULL,NULL,1); + CREATE TABLE tvshowlinkpath (idShow integer, idPath integer); + INSERT INTO "tvshowlinkpath" VALUES(1,2); + CREATE TABLE seasons ( idSeason integer primary key, idShow integer, season integer); + INSERT INTO "seasons" VALUES(1,1,-1); + INSERT INTO "seasons" VALUES(2,1,0); + INSERT INTO "seasons" VALUES(3,1,1); + INSERT INTO "seasons" VALUES(4,1,2); + INSERT INTO "seasons" VALUES(5,1,3); + INSERT INTO "seasons" VALUES(6,1,4); + INSERT INTO "seasons" VALUES(7,1,5); + INSERT INTO "seasons" VALUES(8,1,6); + INSERT INTO "seasons" VALUES(9,1,7); + CREATE TABLE art(art_id INTEGER PRIMARY KEY, media_id INTEGER, media_type TEXT, type TEXT, url TEXT); + INSERT INTO "art" VALUES(1,1,'actor','thumb','http://thetvdb.com/banners/actors/73597.jpg'); + INSERT INTO "art" VALUES(2,2,'actor','thumb','http://thetvdb.com/banners/actors/73596.jpg'); + INSERT INTO "art" VALUES(3,3,'actor','thumb','http://thetvdb.com/banners/actors/73595.jpg'); + INSERT INTO "art" VALUES(4,4,'actor','thumb','http://thetvdb.com/banners/actors/73599.jpg'); + INSERT INTO "art" VALUES(5,5,'actor','thumb','http://thetvdb.com/banners/actors/73598.jpg'); + INSERT INTO "art" VALUES(6,6,'actor','thumb','http://thetvdb.com/banners/actors/283158.jpg'); + INSERT INTO "art" VALUES(7,7,'actor','thumb','http://thetvdb.com/banners/actors/283157.jpg'); + INSERT INTO "art" VALUES(8,8,'actor','thumb','http://thetvdb.com/banners/actors/91271.jpg'); + INSERT INTO "art" VALUES(9,9,'actor','thumb','http://thetvdb.com/banners/actors/294178.jpg'); + INSERT INTO "art" VALUES(10,10,'actor','thumb','http://thetvdb.com/banners/actors/283159.jpg'); + INSERT INTO "art" VALUES(11,1,'tvshow','banner','http://thetvdb.com/banners/graphical/80379-g13.jpg'); + INSERT INTO "art" VALUES(12,1,'tvshow','fanart','http://thetvdb.com/banners/fanart/original/80379-2.jpg'); + INSERT INTO "art" VALUES(13,1,'tvshow','poster','http://thetvdb.com/banners/posters/80379-22.jpg'); + INSERT INTO "art" VALUES(14,1,'season','poster','http://thetvdb.com/banners/posters/80379-22.jpg'); + INSERT INTO "art" VALUES(15,2,'season','banner','http://thetvdb.com/banners/seasonswide/80379-0.jpg'); + INSERT INTO "art" VALUES(16,2,'season','poster','http://thetvdb.com/banners/seasons/80379-0-4.jpg'); + INSERT INTO "art" VALUES(17,3,'season','banner','http://thetvdb.com/banners/seasonswide/80379-1-2.jpg'); + INSERT INTO "art" VALUES(18,3,'season','poster','http://thetvdb.com/banners/seasons/80379-1-12.jpg'); + INSERT INTO "art" VALUES(19,4,'season','banner','http://thetvdb.com/banners/seasonswide/80379-2-2.jpg'); + INSERT INTO "art" VALUES(20,4,'season','poster','http://thetvdb.com/banners/seasons/80379-2-11.jpg'); + INSERT INTO "art" VALUES(21,5,'season','banner','http://thetvdb.com/banners/seasonswide/80379-3-2.jpg'); + INSERT INTO "art" VALUES(22,5,'season','poster','http://thetvdb.com/banners/seasons/80379-3-9.jpg'); + INSERT INTO "art" VALUES(23,6,'season','banner','http://thetvdb.com/banners/seasonswide/80379-4-2.jpg'); + INSERT INTO "art" VALUES(24,6,'season','poster','http://thetvdb.com/banners/seasons/80379-4-8.jpg'); + INSERT INTO "art" VALUES(25,7,'season','banner','http://thetvdb.com/banners/seasonswide/80379-5.jpg'); + INSERT INTO "art" VALUES(26,7,'season','poster','http://thetvdb.com/banners/seasons/80379-5-9.jpg'); + INSERT INTO "art" VALUES(27,8,'season','poster','http://thetvdb.com/banners/seasons/80379-6-8.jpg'); + INSERT INTO "art" VALUES(28,9,'season','poster','http://thetvdb.com/banners/seasons/80379-7-3.jpg'); + INSERT INTO "art" VALUES(29,1,'episode','thumb','http://thetvdb.com/banners/episodes/80379/332484.jpg'); + CREATE INDEX ix_bookmark ON bookmark (idFile, type); + CREATE INDEX ix_path ON path ( strPath ); + CREATE INDEX ix_files ON files ( idPath, strFilename ); + CREATE UNIQUE INDEX ix_episode_file_1 on episode (idEpisode, idFile); + CREATE UNIQUE INDEX id_episode_file_2 on episode (idFile, idEpisode); + CREATE INDEX ix_episode_season_episode on episode (c12, c13); + CREATE INDEX ix_episode_bookmark on episode (c17); + CREATE INDEX ix_episode_show1 on episode(idEpisode,idShow); + CREATE INDEX ix_episode_show2 on episode(idShow,idEpisode); + CREATE UNIQUE INDEX ix_tvshowlinkpath_1 ON tvshowlinkpath ( idShow, idPath ); + CREATE UNIQUE INDEX ix_tvshowlinkpath_2 ON tvshowlinkpath ( idPath, idShow ); + CREATE INDEX ixEpisodeBasePath ON episode ( c19 ); + CREATE INDEX ixTVShowBasePath on tvshow ( c17 ); + CREATE INDEX ix_seasons ON seasons (idShow, season); + CREATE INDEX ix_art ON art(media_id, media_type, type); + CREATE VIEW episodeview + AS + SELECT episode.*, + files.strfilename AS strFileName, + path.strpath AS strPath, + files.playcount AS playCount, + files.lastplayed AS lastPlayed, + files.dateadded AS dateAdded, + tvshow.c00 AS strTitle, + tvshow.c14 AS strStudio, + tvshow.c05 AS premiered, + tvshow.c13 AS mpaa, + tvshow.c16 AS strShowPath, + bookmark.timeinseconds AS resumeTimeInSeconds, + bookmark.totaltimeinseconds AS totalTimeInSeconds, + seasons.idseason AS idSeason + FROM episode + JOIN files + ON files.idfile = episode.idfile + JOIN tvshow + ON tvshow.idshow = episode.idshow + LEFT JOIN seasons + ON seasons.idshow = episode.idshow + AND seasons.season = episode.c12 + JOIN path + ON files.idpath = path.idpath + LEFT JOIN bookmark + ON bookmark.idfile = episode.idfile + AND bookmark.type = 1; + CREATE VIEW tvshowview + AS + SELECT tvshow.*, + path.strpath AS strPath, + path.dateadded AS dateAdded, + Max(files.lastplayed) AS lastPlayed, + NULLIF(Count(episode.c12), 0) AS totalCount, + Count(files.playcount) AS watchedcount, + NULLIF(Count(DISTINCT( episode.c12 )), 0) AS totalSeasons + FROM tvshow + LEFT JOIN tvshowlinkpath + ON tvshowlinkpath.idshow = tvshow.idshow + LEFT JOIN path + ON path.idpath = tvshowlinkpath.idpath + LEFT JOIN episode + ON episode.idshow = tvshow.idshow + LEFT JOIN files + ON files.idfile = episode.idfile + GROUP BY tvshow.idshow; + SELECT + episodeview.c12, + path.strPath, + tvshowview.c00, + tvshowview.c01, + tvshowview.c05, + tvshowview.c08, + tvshowview.c14, + tvshowview.c13, + seasons.idSeason, + count(1), + count(files.playCount) + FROM episodeview + JOIN tvshowview ON tvshowview.idShow = episodeview.idShow + JOIN seasons ON (seasons.idShow = tvshowview.idShow + AND seasons.season = episodeview.c12) + JOIN files ON files.idFile = episodeview.idFile + JOIN tvshowlinkpath ON tvshowlinkpath.idShow = tvshowview.idShow + JOIN path ON path.idPath = tvshowlinkpath.idPath + WHERE tvshowview.idShow = 1 + GROUP BY episodeview.c12; +} {1 /tmp/tvshows/The.Big.Bang.Theory/ {The Big Bang Theory} {Leonard Hofstadter and Sheldon Cooper are brilliant physicists, the kind of "beautiful minds" that understand how the universe works. But none of that genius helps them interact with people, especially women. All this begins to change when a free-spirited beauty named Penny moves in next door. Sheldon, Leonard's roommate, is quite content spending his nights playing Klingon Boggle with their socially dysfunctional friends, fellow CalTech scientists Howard Wolowitz and Raj Koothrappali. However, Leonard sees in Penny a whole new universe of possibilities... including love.} 2007-09-24 Comedy CBS TV-PG 3 1 0} + + finish_test diff --git a/test/trigger2.test b/test/trigger2.test index b4b922a..7b939bd 100644 --- a/test/trigger2.test +++ b/test/trigger2.test @@ -497,7 +497,7 @@ ifcapable conflict { catchsql { INSERT OR ABORT INTO tbl values (2, 2, 3); } - } {1 {column a is not unique}} + } {1 {UNIQUE constraint failed: tbl.a}} do_test trigger2-6.1c { execsql { SELECT * from tbl; @@ -507,7 +507,7 @@ ifcapable conflict { catchsql { INSERT OR FAIL INTO tbl values (2, 2, 3); } - } {1 {column a is not unique}} + } {1 {UNIQUE constraint failed: tbl.a}} do_test trigger2-6.1e { execsql { SELECT * from tbl; @@ -523,7 +523,7 @@ ifcapable conflict { catchsql { INSERT OR ROLLBACK INTO tbl values (3, 2, 3); } - } {1 {column a is not unique}} + } {1 {UNIQUE constraint failed: tbl.a}} do_test trigger2-6.1h { execsql { SELECT * from tbl; @@ -551,7 +551,7 @@ ifcapable conflict { catchsql { UPDATE OR ABORT tbl SET a = 4 WHERE a = 1; } - } {1 {column a is not unique}} + } {1 {UNIQUE constraint failed: tbl.a}} do_test trigger2-6.2c { execsql { SELECT * from tbl; @@ -561,7 +561,7 @@ ifcapable conflict { catchsql { UPDATE OR FAIL tbl SET a = 4 WHERE a = 1; } - } {1 {column a is not unique}} + } {1 {UNIQUE constraint failed: tbl.a}} do_test trigger2-6.2e { execsql { SELECT * from tbl; @@ -583,7 +583,7 @@ ifcapable conflict { catchsql { UPDATE OR ROLLBACK tbl SET a = 4 WHERE a = 1; } - } {1 {column a is not unique}} + } {1 {UNIQUE constraint failed: tbl.a}} do_test trigger2-6.2h { execsql { SELECT * from tbl; diff --git a/test/triggerC.test b/test/triggerC.test index 8d98487..14cc0f0 100644 --- a/test/triggerC.test +++ b/test/triggerC.test @@ -157,7 +157,7 @@ do_test triggerC-1.14 { } {} do_test triggerC-1.15 { catchsql { UPDATE OR ROLLBACK t1 SET a=100 } -} {1 {PRIMARY KEY must be unique}} +} {1 {UNIQUE constraint failed: t1.a}} #------------------------------------------------------------------------- diff --git a/test/triggerE.test b/test/triggerE.test new file mode 100644 index 0000000..e2727bb --- /dev/null +++ b/test/triggerE.test @@ -0,0 +1,112 @@ +# 2009 December 29 +# +# The author disclaims copyright to this source code. In place of +# a legal notice', here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file tests the effects of SQL variable references embedded in +# triggers. If the user attempts to create such a trigger, it is an +# error. However, if an existing trigger definition is read from +# the sqlite_master table, the variable reference always evaluates +# to NULL. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +ifcapable {!trigger} { + finish_test + return +} +set testprefix triggerE + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(c, d); + CREATE TABLE t3(e, f); +} + +# forcedelete test.db2 +# do_execsql_test 1.1 { +# ATTACH 'test.db2' AS aux; +# CREATE TABLE aux.t4(x); +# INSERT INTO aux.t4 VALUES(5); +# +# CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN new.a IN (SELECT x FROM aux.t4) +# BEGIN +# SELECT 1; +# END; +# } +# do_execsql_test 1.2 { INSERT INTO t1 VALUES(1,1); } +# do_execsql_test 1.3 { INSERT INTO t1 VALUES(5,5); } + +#------------------------------------------------------------------------- +# Attempt to create various triggers that use bound variables. +# +set errmsg "trigger cannot use variables" +foreach {tn defn} { + 1 { AFTER INSERT ON t1 WHEN new.a = ? BEGIN SELECT 1; END; } + 2 { BEFORE DELETE ON t1 BEGIN SELECT ?; END; } + 3 { BEFORE DELETE ON t1 BEGIN SELECT * FROM (SELECT * FROM (SELECT ?)); END; } + 5 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 GROUP BY ?; END; } + 6 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 LIMIT ?; END; } + 7 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 ORDER BY ?; END; } + 8 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = ?; END; } + 9 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = 1 WHERE d = ?; END; } +} { + catchsql {drop trigger tr1} + do_catchsql_test 1.1.$tn "CREATE TRIGGER tr1 $defn" [list 1 $errmsg] + do_catchsql_test 1.2.$tn "CREATE TEMP TRIGGER tr1 $defn" [list 1 $errmsg] +} + +#------------------------------------------------------------------------- +# Test that variable references within trigger definitions loaded from +# the sqlite_master table are automatically converted to NULL. +# +do_execsql_test 2.1 { + PRAGMA writable_schema = 1; + INSERT INTO sqlite_master VALUES('trigger', 'tr1', 't1', 0, + 'CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN + INSERT INTO t2 VALUES(?1, ?2); + END' + ); + + INSERT INTO sqlite_master VALUES('trigger', 'tr2', 't3', 0, + 'CREATE TRIGGER tr2 AFTER INSERT ON t3 WHEN ?1 IS NULL BEGIN + UPDATE t2 SET c=d WHERE c IS ?2; + END' + ); +} +db close +sqlite3 db test.db + +do_execsql_test 2.2.1 { + INSERT INTO t1 VALUES(1, 2); + SELECT * FROM t2; +} {{} {}} +do_test 2.2.2 { + set one 3 + execsql { + DELETE FROM t2; + INSERT INTO t1 VALUES($one, ?1); + SELECT * FROM t2; + } +} {{} {}} +do_execsql_test 2.2.3 { SELECT * FROM t1 } {1 2 3 3} + +do_execsql_test 2.3 { + DELETE FROM t2; + INSERT INTO t2 VALUES('x', 'y'); + INSERT INTO t2 VALUES(NULL, 'z'); + INSERT INTO t3 VALUES(1, 2); + SELECT * FROM t3; + SELECT * FROM t2; +} {1 2 x y z z} + +finish_test + + diff --git a/test/unique.test b/test/unique.test index eac19b5..04581c2 100644 --- a/test/unique.test +++ b/test/unique.test @@ -47,8 +47,8 @@ do_test unique-1.3 { catchsql { INSERT INTO t1(a,b,c) VALUES(1,3,4) } -} {1 {column a is not unique}} -verify_ex_errcode unique-1.3b SQLITE_CONSTRAINT_UNIQUE +} {1 {UNIQUE constraint failed: t1.a}} +verify_ex_errcode unique-1.3b SQLITE_CONSTRAINT_PRIMARYKEY do_test unique-1.4 { execsql { SELECT * FROM t1 ORDER BY a; @@ -58,7 +58,7 @@ do_test unique-1.5 { catchsql { INSERT INTO t1(a,b,c) VALUES(3,2,4) } -} {1 {column b is not unique}} +} {1 {UNIQUE constraint failed: t1.b}} verify_ex_errcode unique-1.5b SQLITE_CONSTRAINT_UNIQUE do_test unique-1.6 { execsql { @@ -100,7 +100,7 @@ do_test unique-2.3 { catchsql { INSERT INTO t2 VALUES(1,5); } -} {1 {column a is not unique}} +} {1 {UNIQUE constraint failed: t2.a}} verify_ex_errcode unique-2.3b SQLITE_CONSTRAINT_UNIQUE do_test unique-2.4 { catchsql { @@ -127,7 +127,7 @@ do_test unique-2.8 { catchsql { CREATE UNIQUE INDEX i2 ON t2(a); } -} {1 {indexed columns are not unique}} +} {1 {UNIQUE constraint failed: t2.a}} verify_ex_errcode unique-2.8b SQLITE_CONSTRAINT_UNIQUE do_test unique-2.9 { catchsql { @@ -166,7 +166,7 @@ do_test unique-3.4 { INSERT INTO t3(a,b,c,d) VALUES(1,4,3,5); SELECT * FROM t3 ORDER BY a,b,c,d; } -} {1 {columns a, c, d are not unique}} +} {1 {UNIQUE constraint failed: t3.a, t3.c, t3.d}} verify_ex_errcode unique-3.4b SQLITE_CONSTRAINT_UNIQUE integrity_check unique-3.5 @@ -221,7 +221,7 @@ do_test unique-4.9 { } {0 {}} do_test unique-4.10 { catchsql {CREATE UNIQUE INDEX i4c ON t4(b)} -} {1 {indexed columns are not unique}} +} {1 {UNIQUE constraint failed: t4.b}} verify_ex_errcode unique-4.10b SQLITE_CONSTRAINT_UNIQUE integrity_check unique-4.99 @@ -254,7 +254,7 @@ do_test unique-5.2 { catchsql { INSERT INTO t5 VALUES(1,2,3,4,5,6); } -} {1 {columns first_column_with_long_name, second_column_with_long_name, third_column_with_long_name, fourth_column_with_long_name, fifth_column_with_long_name, sixth_column_with_long_name are not unique}} +} {1 {UNIQUE constraint failed: t5.first_column_with_long_name, t5.second_column_with_long_name, t5.third_column_with_long_name, t5.fourth_column_with_long_name, t5.fifth_column_with_long_name, t5.sixth_column_with_long_name}} verify_ex_errcode unique-5.2b SQLITE_CONSTRAINT_UNIQUE diff --git a/test/unique2.test b/test/unique2.test new file mode 100644 index 0000000..6a320d4 --- /dev/null +++ b/test/unique2.test @@ -0,0 +1,78 @@ +# 2014-07-30 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the CREATE UNIQUE INDEX statement +# to verify that ticket 9a6daf340df99ba93c53bcf8fa83d9f28040d2a8 +# has been fixed: +# +# drh added on 2014-07-30 12:33:04: +# +# The CREATE UNIQUE INDEX on the third line below does not fail even +# though the x column values are not all unique. +# +# CREATE TABLE t1(x NOT NULL); +# INSERT INTO t1 VALUES(1),(2),(2),(3); +# CREATE UNIQUE INDEX t1x ON t1(x); +# +# If the index is created before the INSERT, then uniqueness is enforced +# at the point of the INSERT. Note that the NOT NULL on the indexed column +# seems to be required in order to exhibit this bug. +# +# "PRAGMA integrity_check" does not detect the resulting malformed database. +# That might be considered a separate issue. +# +# Bisecting shows that this problem was introduced by the addition of +# WITHOUT ROWID support in version 3.8.2, specifically in check-in +# [c80e229dd9c1230] on 2013-11-07. This problem was reported on the mailing +# list by Pavel Pimenov. and primary keys, and the UNIQUE constraint +# on table columns +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +foreach {id sql} { + 1 {CREATE TABLE t1(x TEXT PRIMARY KEY, y NOT NULL) WITHOUT ROWID} + 2 {CREATE TABLE t1(x TEXT PRIMARY KEY, y NOT NULL)} + 3 {CREATE TABLE t1(x TEXT PRIMARY KEY, y) WITHOUT ROWID} + 4 {CREATE TABLE t1(x TEXT PRIMARY KEY, y)} +} { + do_test $id.1 { + db eval {DROP TABLE IF EXISTS t1} + db eval $sql + db eval {INSERT INTO t1(x,y) VALUES(1,1),(2,2),(3,2),(4,3)} + } {} + do_test $id.2 { + catchsql {CREATE UNIQUE INDEX t1y ON t1(y)} + } {1 {UNIQUE constraint failed: t1.y}} +} + +foreach {id sql} { + 5 {CREATE TABLE t1(w,x,y NOT NULL,z NOT NULL,PRIMARY KEY(w,x)) WITHOUT ROWID} + 6 {CREATE TABLE t1(w,x,y NOT NULL,z NOT NULL,PRIMARY KEY(w,x))} + 7 {CREATE TABLE t1(w,x,y NOT NULL,z,PRIMARY KEY(w,x)) WITHOUT ROWID} + 8 {CREATE TABLE t1(w,x,y NOT NULL,z,PRIMARY KEY(w,x))} + 9 {CREATE TABLE t1(w,x,y,z NOT NULL,PRIMARY KEY(w,x)) WITHOUT ROWID} + 10 {CREATE TABLE t1(w,x,y,z NOT NULL,PRIMARY KEY(w,x))} + 11 {CREATE TABLE t1(w,x,y,z,PRIMARY KEY(w,x)) WITHOUT ROWID} + 12 {CREATE TABLE t1(w,x,y,z,PRIMARY KEY(w,x))} +} { + do_test $id.1 { + db eval {DROP TABLE IF EXISTS t1} + db eval $sql + db eval {INSERT INTO t1(w,x,y,z) VALUES(1,2,3,4),(2,3,3,4)} + } {} + do_test $id.2 { + catchsql {CREATE UNIQUE INDEX t1yz ON t1(y,z)} + } {1 {UNIQUE constraint failed: t1.y, t1.z}} +} + +finish_test diff --git a/test/unixexcl.test b/test/unixexcl.test index 0147e6b..d676217 100644 --- a/test/unixexcl.test +++ b/test/unixexcl.test @@ -109,7 +109,7 @@ do_multiclient_test tn { } {1 2} do_test unixexcl-3.$tn.3 { sql1 { PRAGMA wal_checkpoint; INSERT INTO t1 VALUES(3, 4); } - } {0 3 3} + } {0 5 5} do_test unixexcl-3.$tn.4 { sql2 { SELECT * FROM t1; } } {1 2} @@ -121,7 +121,7 @@ do_multiclient_test tn { } {1 2 3 4} do_test unixexcl-3.$tn.7 { sql1 { PRAGMA wal_checkpoint; } - } {0 4 4} + } {0 7 7} } } diff --git a/test/unordered.test b/test/unordered.test index 4aa8310..147e91f 100644 --- a/test/unordered.test +++ b/test/unordered.test @@ -40,28 +40,28 @@ foreach idxmode {ordered unordered} { sqlite3 db test.db foreach {tn sql r(ordered) r(unordered)} { 1 "SELECT * FROM t1 ORDER BY a" - {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}} - {0 0 0 {SCAN TABLE t1 (~128 rows)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} - 2 "SELECT * FROM t1 WHERE a >?" - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~32 rows)}} - {0 0 0 {SCAN TABLE t1 (~42 rows)}} + {0 0 0 {SCAN TABLE t1 USING INDEX i1}} + {0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} + 2 "SELECT * FROM t1 WHERE a > 100" + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} + {0 0 0 {SCAN TABLE t1}} 3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid" - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}} - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)} + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} 4 "SELECT max(a) FROM t1" - {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (~1 rows)}} - {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (~1 rows)}} + {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1}} + {0 0 0 {SEARCH TABLE t1}} 5 "SELECT group_concat(b) FROM t1 GROUP BY a" - {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}} - {0 0 0 {SCAN TABLE t1 (~128 rows)} 0 0 0 {USE TEMP B-TREE FOR GROUP BY}} + {0 0 0 {SCAN TABLE t1 USING INDEX i1}} + {0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY}} 6 "SELECT * FROM t1 WHERE a = ?" - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}} - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}} + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} 7 "SELECT count(*) FROM t1" - {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1(~128 rows)}} - {0 0 0 {SCAN TABLE t1 (~128 rows)}} + {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}} + {0 0 0 {SCAN TABLE t1}} } { do_eqp_test 1.$idxmode.$tn $sql $r($idxmode) } diff --git a/test/update.test b/test/update.test index a6fef7d..e67b0ef 100644 --- a/test/update.test +++ b/test/update.test @@ -452,7 +452,7 @@ do_test update-10.3 { UPDATE t1 SET a=1, e=10 WHERE f=7; SELECT * FROM t1; } -} {1 {PRIMARY KEY must be unique}} +} {1 {UNIQUE constraint failed: t1.a}} do_test update-10.4 { catchsql { SELECT * FROM t1; @@ -469,7 +469,7 @@ do_test update-10.6 { UPDATE t1 SET b=2, e=12 WHERE f=7; SELECT * FROM t1; } -} {1 {column b is not unique}} +} {1 {UNIQUE constraint failed: t1.b}} do_test update-10.7 { catchsql { SELECT * FROM t1; @@ -486,7 +486,7 @@ do_test update-10.9 { UPDATE t1 SET c=3, d=4, e=14 WHERE f=7; SELECT * FROM t1; } -} {1 {columns c, d are not unique}} +} {1 {UNIQUE constraint failed: t1.c, t1.d}} do_test update-10.10 { catchsql { SELECT * FROM t1; diff --git a/test/uri.test b/test/uri.test index af1ad67..dd78783 100644 --- a/test/uri.test +++ b/test/uri.test @@ -238,12 +238,14 @@ ifcapable wal { tvfs1 script tvfs1_callback proc tvfs1_callback {method filename args} { set ::T1([file tail $filename]) 1 + return SQLITE_OK } testvfs tvfs2 tvfs2 filter {xOpen xDelete xAccess xFullPathname} tvfs2 script tvfs2_callback proc tvfs2_callback {method filename args} { set ::T2([file tail $filename]) 1 + return SQLITE_OK } catch {db close} diff --git a/test/veryquick.test b/test/veryquick.test index ca82b22..c8d6ce8 100644 --- a/test/veryquick.test +++ b/test/veryquick.test @@ -16,4 +16,3 @@ source $testdir/permutations.test run_test_suite veryquick finish_test - diff --git a/test/view.test b/test/view.test index 779f77b..3ba6c0b 100644 --- a/test/view.test +++ b/test/view.test @@ -611,4 +611,17 @@ ifcapable progress { } {1 interrupted} } +db close +sqlite3 db :memory: +do_execsql_test view-22.1 { + CREATE VIEW x1 AS SELECT 123 AS '', 234 AS '', 345 AS ''; + SELECT * FROM x1; +} {123 234 345} +do_test view-22.2 { + unset -nocomplain x + db eval {SELECT * FROM x1} x break + lsort [array names x] +} {{} * :1 :2} + + finish_test diff --git a/test/vtab1.test b/test/vtab1.test index 1f17e53..0542ee6 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -618,8 +618,9 @@ do_test vtab1-5-6 { do_test vtab1-5-7 { filter $::echo_module } [list \ - xFilter {SELECT rowid, * FROM 't2' WHERE d = ?} \ xFilter {SELECT rowid, * FROM 't1'} \ + xFilter {SELECT rowid, * FROM 't2' WHERE d = ?} \ + xFilter {SELECT rowid, * FROM 't2' WHERE d = ?} \ ] execsql { @@ -1039,10 +1040,10 @@ do_test vtab1.12-1 { # First test outside of a transaction. do_test vtab1.12-2 { catchsql { INSERT INTO echo_c SELECT * FROM b; } -} {1 {echo-vtab-error: column a is not unique}} +} {1 {echo-vtab-error: UNIQUE constraint failed: c.a}} do_test vtab1.12-2.1 { sqlite3_errmsg db -} {echo-vtab-error: column a is not unique} +} {echo-vtab-error: UNIQUE constraint failed: c.a} do_test vtab1.12-3 { execsql { SELECT * FROM c } } {3 G H} @@ -1051,7 +1052,7 @@ do_test vtab1.12-3 { do_test vtab1.12-4 { execsql {BEGIN} catchsql { INSERT INTO echo_c SELECT * FROM b; } -} {1 {echo-vtab-error: column a is not unique}} +} {1 {echo-vtab-error: UNIQUE constraint failed: c.a}} do_test vtab1.12-5 { execsql { SELECT * FROM c } } {3 G H} @@ -1133,12 +1134,12 @@ do_test vtab1-14.015 { -do_test vtab1-14.1 { - execsql { DELETE FROM c } - set echo_module "" - execsql { SELECT * FROM echo_c WHERE rowid IN (1, 2, 3) } - set echo_module -} {/xBestIndex {SELECT rowid, . FROM 'c' WHERE rowid = .} xFilter {SELECT rowid, . FROM 'c' WHERE rowid = .} 1/} +#do_test vtab1-14.1 { +# execsql { DELETE FROM c } +# set echo_module "" +# execsql { SELECT * FROM echo_c WHERE rowid IN (1, 2, 3) } +# set echo_module +#} {/.*xBestIndex {SELECT rowid, . FROM 'c' WHERE rowid = .} xFilter {SELECT rowid, . FROM 'c'} 1/} do_test vtab1-14.2 { set echo_module "" @@ -1152,11 +1153,11 @@ do_test vtab1-14.3 { set echo_module } [list xBestIndex {SELECT rowid, * FROM 'c' WHERE a = ?} xFilter {SELECT rowid, * FROM 'c' WHERE a = ?} 1] -do_test vtab1-14.4 { - set echo_module "" - execsql { SELECT * FROM echo_c WHERE a IN (1, 2) } - set echo_module -} {/xBestIndex {SELECT rowid, . FROM 'c' WHERE a = .} xFilter {SELECT rowid, . FROM 'c' WHERE a = .} 1/} +#do_test vtab1-14.4 { +# set echo_module "" +# execsql { SELECT * FROM echo_c WHERE a IN (1, 2) } +# set echo_module +#} {/xBestIndex {SELECT rowid, . FROM 'c' WHERE a = .} xFilter {SELECT rowid, . FROM 'c' WHERE a = .} 1/} do_test vtab1-15.1 { execsql { @@ -1375,4 +1376,23 @@ do_execsql_test 20.4 { ORDER BY 1, 2; } {5 5 6 6 11 11 12 12} +#------------------------------------------------------------------------- +# +do_execsql_test 21.1 { + CREATE TABLE t9(a,b,c); + CREATE VIRTUAL TABLE t9v USING echo(t9); + + INSERT INTO t9 VALUES(1,2,3); + INSERT INTO t9 VALUES(3,2,1); + INSERT INTO t9 VALUES(2,2,2); +} + +do_execsql_test 21.2 { + SELECT * FROM t9v WHERE a<b; +} {1 2 3} + +do_execsql_test 21.3 { + SELECT * FROM t9v WHERE a=b; +} {2 2 2} + finish_test diff --git a/test/vtab6.test b/test/vtab6.test index 96e45bf..10bf286 100644 --- a/test/vtab6.test +++ b/test/vtab6.test @@ -561,12 +561,12 @@ do_test vtab6-11.4.1 { catchsql { SELECT a, b, c FROM ab NATURAL JOIN bc; } -} {1 {table bc: xBestIndex returned an invalid plan}} +} {1 {table ab: xBestIndex returned an invalid plan}} do_test vtab6-11.4.2 { catchsql { SELECT a, b, c FROM bc NATURAL JOIN ab; } -} {1 {table ab: xBestIndex returned an invalid plan}} +} {1 {table bc: xBestIndex returned an invalid plan}} unset ::echo_module_ignore_usable diff --git a/test/vtab_shared.test b/test/vtab_shared.test index 6a76e27..3473992 100644 --- a/test/vtab_shared.test +++ b/test/vtab_shared.test @@ -15,6 +15,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix vtab_shared ifcapable !vtab||!shared_cache { finish_test @@ -116,7 +117,6 @@ do_test vtab_shared-1.10 { } {1 {database table is locked: sqlite_master}} do_test vtab_shared-1.11 { -breakpoint execsql { CREATE VIRTUAL TABLE t2 USING echo(t0); CREATE VIRTUAL TABLE t3 USING echo(t0); @@ -229,5 +229,51 @@ do_test vtab_shared_1.15.3 { db close db2 close + +#--------------------------------------------------------------- +# Test calling sqlite3_close() with vtabs on the disconnect list. +# +ifcapable rtree { + reset_db + do_test 2.1.1 { + sqlite3 db test.db + sqlite3 db2 test.db + + # Create a virtual table using [db]. + execsql { + CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2); + INSERT INTO rt VALUES(1, 2 ,3); + SELECT * FROM rt; + } + + # Drop the virtual table using [db2]. The sqlite3_vtab object belonging + # to [db] is moved to the sqlite3.pDisconnect list. + execsql { DROP TABLE rt } db2 + + # Immediately close [db]. At one point this would fail due to the + # unfinalized statements held by the un-xDisconnect()ed sqlite3_vtab. + db close + } {} + db2 close +} + +ifcapable fts3 { + # Same test as above, except using fts3 instead of rtree. + reset_db + do_test 2.2.1 { + sqlite3 db test.db + sqlite3 db2 test.db + execsql { + CREATE VIRTUAL TABLE ft USING fts3; + INSERT INTO ft VALUES('hello world'); + SELECT * FROM ft; + } + execsql { DROP TABLE ft } db2 + db close + } {} + db2 close +} + sqlite3_enable_shared_cache 0 finish_test + diff --git a/test/wal.test b/test/wal.test index c8078a1..675be73 100644 --- a/test/wal.test +++ b/test/wal.test @@ -322,7 +322,7 @@ do_test wal-5.4 { INSERT INTO t3 VALUES('abc'); } catchsql { INSERT INTO t3 VALUES('abc') } -} {1 {column x is not unique}} +} {1 {UNIQUE constraint failed: t3.x}} do_test wal-5.5 { execsql { COMMIT; @@ -852,7 +852,6 @@ do_test wal-13.1.2 { sqlite3 db test.db execsql { SELECT * FROM t2 } } {B 2} -breakpoint do_test wal-13.1.3 { db close file exists test.db-wal @@ -1575,4 +1574,17 @@ sqlite3_shutdown test_sqlite3_log sqlite3_initialize +# Make sure PRAGMA journal_mode=WAL works with ATTACHED databases in +# all journal modes. +# +foreach mode {OFF MEMORY PERSIST DELETE TRUNCATE WAL} { + delete_file test.db test2.db + sqlite3 db test.db + do_test wal-25.$mode { + db eval "PRAGMA journal_mode=$mode" + db eval {ATTACH 'test2.db' AS t2; PRAGMA journal_mode=WAL;} + } {wal} + db close +} + finish_test diff --git a/test/wal2.test b/test/wal2.test index 4371e98..9d45444 100644 --- a/test/wal2.test +++ b/test/wal2.test @@ -811,7 +811,13 @@ do_test wal2-7.1.1 { do_test wal2-7.1.2 { forcecopy test.db test2.db forcecopy test.db-wal test2.db-wal - hexio_write test2.db-wal 48 FF + # The first 32 bytes of the WAL file contain the WAL header. Offset 48 + # is the first byte of the checksum for the first frame in the WAL. + # The following three lines replaces the contents of that byte with + # a different value. + set newval FF + if {$newval == [hexio_read test2.db-wal 48 1]} { set newval 00 } + hexio_write test2.db-wal 48 $newval } {1} do_test wal2-7.1.3 { sqlite3 db2 test2.db @@ -1279,7 +1285,6 @@ foreach {tn settings restart_sync commit_sync ckpt_sync} { PRAGMA synchronous = [lindex $settings 2]; " {0 wal} -if { $tn==2} breakpoint do_test 15.$tn.2 { set sync(normal) 0 set sync(full) 0 diff --git a/test/wal6.test b/test/wal6.test index ec31bb8..2498907 100644 --- a/test/wal6.test +++ b/test/wal6.test @@ -14,6 +14,7 @@ # set testdir [file dirname $argv0] +set testprefix wal6 source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/wal_common.tcl @@ -29,18 +30,18 @@ forcedelete test.db set all_journal_modes {delete persist truncate memory off} foreach jmode $all_journal_modes { - do_test wal6-1.0.$jmode { + do_test wal6-1.0.$jmode { sqlite3 db test.db execsql "PRAGMA journal_mode = $jmode;" - } $jmode + } $jmode - do_test wal6-1.1.$jmode { - execsql { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b); - INSERT INTO t1 VALUES(1,2); - SELECT * FROM t1; - } - } {1 2} + do_test wal6-1.1.$jmode { + execsql { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + INSERT INTO t1 VALUES(1,2); + SELECT * FROM t1; + } + } {1 2} # Under Windows, you'll get an error trying to delete # a file this is already opened. Close the first connection @@ -51,31 +52,146 @@ if {$tcl_platform(platform)=="windows"} { } } - do_test wal6-1.2.$jmode { - sqlite3 db2 test.db - execsql { - PRAGMA journal_mode=WAL; - INSERT INTO t1 VALUES(3,4); - SELECT * FROM t1 ORDER BY a; - } db2 - } {wal 1 2 3 4} + do_test wal6-1.2.$jmode { + sqlite3 db2 test.db + execsql { + PRAGMA journal_mode=WAL; + INSERT INTO t1 VALUES(3,4); + SELECT * FROM t1 ORDER BY a; + } db2 + } {wal 1 2 3 4} if {$tcl_platform(platform)=="windows"} { if {$jmode=="persist" || $jmode=="truncate"} { - sqlite3 db test.db + sqlite3 db test.db } } - do_test wal6-1.3.$jmode { - execsql { - SELECT * FROM t1 ORDER BY a; - } - } {1 2 3 4} + do_test wal6-1.3.$jmode { + execsql { + SELECT * FROM t1 ORDER BY a; + } + } {1 2 3 4} - db close - db2 close + db close + db2 close forcedelete test.db } +#------------------------------------------------------------------------- +# Test that SQLITE_BUSY_SNAPSHOT is returned as expected. +# +reset_db +sqlite3 db2 test.db + +do_execsql_test 2.1 { + PRAGMA journal_mode = WAL; + CREATE TABLE t1(a PRIMARY KEY, b TEXT); + INSERT INTO t1 VALUES(1, 'one'); + INSERT INTO t1 VALUES(2, 'two'); + BEGIN; + SELECT * FROM t1; +} {wal 1 one 2 two} + +do_test 2.2 { + execsql { + SELECT * FROM t1; + INSERT INTO t1 VALUES(3, 'three'); + } db2 +} {1 one 2 two} + +do_catchsql_test 2.3 { + INSERT INTO t1 VALUES('x', 'x') +} {1 {database is locked}} + +do_test 2.4 { + list [sqlite3_errcode db] [sqlite3_extended_errcode db] +} {SQLITE_BUSY SQLITE_BUSY_SNAPSHOT} + +do_execsql_test 2.5 { + SELECT * FROM t1; + COMMIT; + INSERT INTO t1 VALUES('x', 'x') +} {1 one 2 two} + +proc test3 {prefix} { + do_test $prefix.1 { + execsql { SELECT count(*) FROM t1 } + } {0} + do_test $prefix.2 { + execsql { INSERT INTO t1 VALUES('x', 'x') } db2 + } {} + do_test $prefix.3 { + execsql { INSERT INTO t1 VALUES('y', 'y') } + } {} + do_test $prefix.4 { + execsql { SELECT count(*) FROM t1 } + } {2} +} + +do_execsql_test 2.6.1 { DELETE FROM t1 } +test3 2.6.2 + +db func test3 test3 +do_execsql_test 2.6.3 { DELETE FROM t1 } +db eval {SELECT test3('2.6.4')} + +do_test 2.x { + db2 close +} {} + +#------------------------------------------------------------------------- +# Check that if BEGIN IMMEDIATE fails, it does not leave the user with +# an open read-transaction (unless one was already open before the BEGIN +# IMMEDIATE). Even if there are other active VMs. +# + +proc test4 {prefix} { + do_test $prefix.1 { + catchsql { BEGIN IMMEDIATE } + } {1 {database is locked}} + + do_test $prefix.2 { + execsql { COMMIT } db2 + } {} + + do_test $prefix.3 { + execsql { BEGIN IMMEDIATE } + } {} + do_test $prefix.4 { + execsql { COMMIT } + } {} +} + +reset_db +sqlite3 db2 test.db +do_execsql_test 3.1 { + PRAGMA journal_mode = WAL; + CREATE TABLE ab(a PRIMARY KEY, b); +} {wal} + +do_test 3.2.1 { + execsql { + BEGIN; + INSERT INTO ab VALUES(1, 2); + } db2 +} {} +test4 3.2.2 + +db func test4 test4 +do_test 3.3.1 { + execsql { + BEGIN; + INSERT INTO ab VALUES(3, 4); + } db2 +} {} + +db eval {SELECT test4('3.3.2')} + +do_test 3.x { + db2 close +} {} + finish_test + diff --git a/test/wal64k.test b/test/wal64k.test new file mode 100644 index 0000000..e962da1 --- /dev/null +++ b/test/wal64k.test @@ -0,0 +1,51 @@ +# 2010 April 13 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the operation of the library in +# "PRAGMA journal_mode=WAL" mode. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix wal64k + +ifcapable !wal {finish_test ; return } + +if {$tcl_platform(platform) != "unix"} { + finish_test + return +} + +db close +test_syscall pagesize 65536 +sqlite3 db test.db + +do_execsql_test 1.0 { + PRAGMA journal_mode = WAL; + CREATE TABLE t1(x); + CREATE INDEX i1 ON t1(x); +} {wal} +do_test 1.1 { file size test.db-shm } {65536} + +do_test 1.2 { + execsql BEGIN + while {[file size test.db-shm]==65536} { + execsql { INSERT INTO t1 VALUES( randstr(900,1100) ) } + } + execsql COMMIT + file size test.db-shm +} {131072} + +integrity_check 1.3 + +db close +test_syscall pagesize -1 +finish_test diff --git a/test/wal8.test b/test/wal8.test index 3399538..0682fce 100644 --- a/test/wal8.test +++ b/test/wal8.test @@ -88,4 +88,3 @@ do_execsql_test 3.1 { } {t1} finish_test - diff --git a/test/walcksum.test b/test/walcksum.test index 08278dd..3005a75 100644 --- a/test/walcksum.test +++ b/test/walcksum.test @@ -390,4 +390,3 @@ foreach incr {1 2 3 20 40 60 80 100 120 140 160 180 200 220 240 253 254 255} { } finish_test - diff --git a/test/walcrash.test b/test/walcrash.test index adc4841..2a64718 100644 --- a/test/walcrash.test +++ b/test/walcrash.test @@ -293,4 +293,3 @@ for {set i 1} {$i < $REPEATS} {incr i} { } finish_test - diff --git a/test/walcrash2.test b/test/walcrash2.test index 7116281..9c93bcd 100644 --- a/test/walcrash2.test +++ b/test/walcrash2.test @@ -96,4 +96,3 @@ do_test walcrash2-1.3 { catch { db2 close } finish_test - diff --git a/test/walcrash3.test b/test/walcrash3.test index c2c9a6d..71dfb45 100644 --- a/test/walcrash3.test +++ b/test/walcrash3.test @@ -126,4 +126,3 @@ for {set i 2} {$i<10000 && [set_test_counter errors]==$nInitialErr} {incr i} { } finish_test - diff --git a/test/walfault.test b/test/walfault.test index 4a9d98a..4e7064d 100644 --- a/test/walfault.test +++ b/test/walfault.test @@ -567,7 +567,6 @@ do_test walfault-14-pre { } {} do_faultsim_test walfault-14 -prep { faultsim_restore_and_reopen - breakpoint execsql { SELECT count(*) FROM abc; PRAGMA locking_mode = exclusive; diff --git a/test/walro.test b/test/walro.test index 465ce83..6d920b1 100644 --- a/test/walro.test +++ b/test/walro.test @@ -32,9 +32,6 @@ ifcapable !wal { } do_multiclient_test tn { - # Do not run tests with the connections in the same process. - # - if {$tn==2} continue # Close all connections and delete the database. # @@ -43,6 +40,10 @@ do_multiclient_test tn { code3 { db3 close } forcedelete test.db forcedelete walro + + # Do not run tests with the connections in the same process. + # + if {$tn==2} continue foreach c {code1 code2 code3} { $c { @@ -232,9 +233,6 @@ forcedelete test.db # database file while a checkpoint operation is ongoing. # do_multiclient_test tn { - # Do not run tests with the connections in the same process. - # - if {$tn==2} continue # Close all connections and delete the database. # @@ -243,6 +241,10 @@ do_multiclient_test tn { code3 { db3 close } forcedelete test.db forcedelete walro + + # Do not run tests with the connections in the same process. + # + if {$tn==2} continue foreach c {code1 code2 code3} { $c { @@ -291,5 +293,3 @@ do_multiclient_test tn { } finish_test - - diff --git a/test/walshared.test b/test/walshared.test index 73a3fb8..fbbdeb4 100644 --- a/test/walshared.test +++ b/test/walshared.test @@ -60,4 +60,3 @@ do_test walshared-1.4 { sqlite3_enable_shared_cache $::enable_shared_cache finish_test - diff --git a/test/where.test b/test/where.test index 2dbc283..f560708 100644 --- a/test/where.test +++ b/test/where.test @@ -65,9 +65,9 @@ proc count sql { do_test where-1.1.1 { count {SELECT x, y, w FROM t1 WHERE w=10} } {3 121 10 3} -do_test where-1.1.2 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.1.2 { + SELECT x, y, w FROM t1 WHERE w=10 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.1.3 { db status step } {0} @@ -77,15 +77,15 @@ do_test where-1.1.4 { do_test where-1.1.5 { db status step } {99} -do_test where-1.1.6 { - set sqlite_query_plan -} {t1 {}} +do_eqp_test where-1.1.6 { + SELECT x, y, w FROM t1 WHERE +w=10 +} {*SCAN TABLE t1*} do_test where-1.1.7 { count {SELECT x, y, w AS abc FROM t1 WHERE abc=10} } {3 121 10 3} -do_test where-1.1.8 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.1.8 { + SELECT x, y, w AS abc FROM t1 WHERE abc=10 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.1.9 { db status step } {0} @@ -104,21 +104,21 @@ do_test where-1.3.2 { do_test where-1.4.1 { count {SELECT w, x, y FROM t1 WHERE 11=w AND x>2} } {11 3 144 3} -do_test where-1.4.2 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.4.2 { + SELECT w, x, y FROM t1 WHERE 11=w AND x>2 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.4.3 { count {SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2} } {11 3 144 3} -do_test where-1.4.4 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.4.4 { + SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.5 { count {SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2} } {3 144 3} -do_test where-1.5.2 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.5.2 { + SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.6 { count {SELECT x, y FROM t1 WHERE y<200 AND x>2 AND w=11} } {3 144 3} @@ -128,13 +128,12 @@ do_test where-1.7 { do_test where-1.8 { count {SELECT x, y FROM t1 WHERE w>10 AND y=144 AND x=3} } {3 144 3} -do_test where-1.8.2 { - set sqlite_query_plan -} {t1 i1xy} -do_test where-1.8.3 { - count {SELECT x, y FROM t1 WHERE y=144 AND x=3} - set sqlite_query_plan -} {{} i1xy} +do_eqp_test where-1.8.2 { + SELECT x, y FROM t1 WHERE w>10 AND y=144 AND x=3 +} {*SEARCH TABLE t1 USING INDEX i1xy (x=? AND y=?)*} +do_eqp_test where-1.8.3 { + SELECT x, y FROM t1 WHERE y=144 AND x=3 +} {*SEARCH TABLE t1 USING COVERING INDEX i1xy (x=? AND y=?)*} do_test where-1.9 { count {SELECT x, y FROM t1 WHERE y=144 AND w>10 AND x=3} } {3 144 3} @@ -238,10 +237,10 @@ do_test where-1.34 { } {97 99} do_test where-1.35 { count {SELECT w FROM t1 WHERE w<3} -} {1 2 2} +} {1 2 3} do_test where-1.36 { count {SELECT w FROM t1 WHERE w<=3} -} {1 2 3 3} +} {1 2 3 4} do_test where-1.37 { count {SELECT w FROM t1 WHERE w+1<=4 ORDER BY w} } {1 2 3 99} @@ -605,7 +604,7 @@ do_test where-6.9.7 { cksort { SELECT * FROM t3 WHERE a=1 AND c>0 ORDER BY c,a LIMIT 3 } -} {1 100 4 sort} +} {1 100 4 nosort} do_test where-6.9.8 { cksort { SELECT * FROM t3 WHERE a=1 AND c>0 ORDER BY a DESC, c ASC LIMIT 3 @@ -1126,9 +1125,9 @@ do_test where-13.12 { if {[permutation] != "no_optimization"} { do_test where-14.1 { execsql { - CREATE TABLE t8(a INTEGER PRIMARY KEY, b TEXT UNIQUE); - INSERT INTO t8 VALUES(1,'one'); - INSERT INTO t8 VALUES(4,'four'); + CREATE TABLE t8(a INTEGER PRIMARY KEY, b TEXT UNIQUE, c CHAR(100)); + INSERT INTO t8(a,b) VALUES(1,'one'); + INSERT INTO t8(a,b) VALUES(4,'four'); } cksort { SELECT x.a || '/' || y.a FROM t8 x, t8 y ORDER BY x.a, y.b @@ -1305,4 +1304,33 @@ do_test where-17.5 { } } {42 1 43 1} +# Ticket [be84e357c035d068135f20bcfe82761bbf95006b] 2013-09-03 +# Segfault during query involving LEFT JOIN column in the ORDER BY clause. +# +do_execsql_test where-18.1 { + CREATE TABLE t181(a); + CREATE TABLE t182(b,c); + INSERT INTO t181 VALUES(1); + SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL; +} {1} +do_execsql_test where-18.2 { + SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c; +} {1} +do_execsql_test where-18.3 { + SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c; +} {1} +do_execsql_test where-18.4 { + INSERT INTO t181 VALUES(1),(1),(1),(1); + SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c; +} {1} +do_execsql_test where-18.5 { + INSERT INTO t181 VALUES(2); + SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL, +a; +} {1 2} +do_execsql_test where-18.6 { + INSERT INTO t181 VALUES(2); + SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +a, +c IS NULL; +} {1 2} + + finish_test diff --git a/test/where2.test b/test/where2.test index e8c2f36..367eb0d 100644 --- a/test/where2.test +++ b/test/where2.test @@ -66,14 +66,24 @@ proc cksort {sql} { # This procedure executes the SQL. Then it appends to the result the # "sort" or "nosort" keyword (as in the cksort procedure above) then -# it appends the ::sqlite_query_plan variable. +# it appends the name of the table and index used. # proc queryplan {sql} { set ::sqlite_sort_count 0 set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x - return [concat $data $::sqlite_query_plan] + set eqp [execsql "EXPLAIN QUERY PLAN $sql"] + # puts eqp=$eqp + foreach {a b c x} $eqp { + if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ + $x all as tab idx]} { + lappend data $tab $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { + lappend data $tab * + } + } + return $data } @@ -111,6 +121,42 @@ do_test where2-2.3 { } } {85 6 7396 7402 nosort t1 *} +# Ticket [65bdeb9739605cc22966f49208452996ff29a640] 2014-02-26 +# Make sure "ORDER BY random" does not gets optimized out. +# +do_test where2-2.4 { + db eval { + CREATE TABLE x1(a INTEGER PRIMARY KEY, b DEFAULT 1); + WITH RECURSIVE + cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<50) + INSERT INTO x1 SELECT x, 1 FROM cnt; + CREATE TABLE x2(x INTEGER PRIMARY KEY); + INSERT INTO x2 VALUES(1); + } + set sql {SELECT * FROM x1, x2 WHERE x=1 ORDER BY random()} + set out1 [db eval $sql] + set out2 [db eval $sql] + set out3 [db eval $sql] + expr {$out1!=$out2 && $out2!=$out3} +} {1} +do_execsql_test where2-2.5 { + -- random() is not optimized out + EXPLAIN SELECT * FROM x1, x2 WHERE x=1 ORDER BY random(); +} {/ random/} +do_execsql_test where2-2.5b { + -- random() is not optimized out + EXPLAIN SELECT * FROM x1, x2 WHERE x=1 ORDER BY random(); +} {/ SorterOpen /} +do_execsql_test where2-2.6 { + -- other constant functions are optimized out + EXPLAIN SELECT * FROM x1, x2 WHERE x=1 ORDER BY abs(5); +} {~/ abs/} +do_execsql_test where2-2.6b { + -- other constant functions are optimized out + EXPLAIN SELECT * FROM x1, x2 WHERE x=1 ORDER BY abs(5); +} {~/ SorterOpen /} + + # Efficient handling of forward and reverse table scans. # @@ -273,12 +319,12 @@ do_test where2-6.3 { queryplan { SELECT * FROM t1 WHERE w=99 OR w=100 OR 6=+w ORDER BY +w } -} {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 {}} +} {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 *} do_test where2-6.4 { queryplan { SELECT * FROM t1 WHERE w=99 OR +w=100 OR 6=w ORDER BY +w } -} {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 {}} +} {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 *} set ::idx {} ifcapable subquery {set ::idx i1zyx} @@ -297,14 +343,16 @@ do_test where2-6.6 { } } [list 1 0 4 4 2 1 9 10 sort a i1w b $::idx] +if {[permutation] != "no_optimization"} { + # Ticket #2249. Make sure the OR optimization is not attempted if # comparisons between columns of different affinities are needed. # do_test where2-6.7 { execsql { - CREATE TABLE t2249a(a TEXT UNIQUE); + CREATE TABLE t2249a(a TEXT UNIQUE, x CHAR(100)); CREATE TABLE t2249b(b INTEGER); - INSERT INTO t2249a VALUES('0123'); + INSERT INTO t2249a(a) VALUES('0123'); INSERT INTO t2249b VALUES(123); } queryplan { @@ -312,56 +360,56 @@ do_test where2-6.7 { -- will attempt to convert to NUMERIC before the comparison. -- They will thus compare equal. -- - SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=b; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.9 { queryplan { -- The + operator removes affinity from the rhs. No conversions -- occur and the comparison is false. The result is an empty set. -- - SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=+b; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b; } -} {nosort t2249b {} {} sqlite_autoindex_t2249a_1} +} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.9.2 { # The same thing but with the expression flipped around. queryplan { - SELECT * FROM t2249b CROSS JOIN t2249a WHERE +b=a + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a } -} {nosort t2249b {} {} sqlite_autoindex_t2249a_1} +} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.10 { queryplan { -- Use + on both sides of the comparison to disable indices -- completely. Make sure we get the same result. -- - SELECT * FROM t2249b CROSS JOIN t2249a WHERE +a=+b; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +a=+b; } -} {nosort t2249b {} t2249a {}} +} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.11 { # This will not attempt the OR optimization because of the a=b # comparison. queryplan { - SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello'; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello'; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.11.2 { # Permutations of the expression terms. queryplan { - SELECT * FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello'; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello'; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.11.3 { # Permutations of the expression terms. queryplan { - SELECT * FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.11.4 { # Permutations of the expression terms. queryplan { - SELECT * FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} ifcapable explain&&subquery { # These tests are not run if subquery support is not included in the # build. This is because these tests test the "a = 1 OR a = 2" to @@ -373,41 +421,41 @@ ifcapable explain&&subquery { # the OR optimization to be used again. The result is now an empty # set, the same as in where2-6.9. queryplan { - SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello'; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello'; } - } {nosort t2249b {} {} sqlite_autoindex_t2249a_1} + } {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.12.2 { # In this case, the +b disables the affinity conflict and allows # the OR optimization to be used again. The result is now an empty # set, the same as in where2-6.9. queryplan { - SELECT * FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a; } - } {nosort t2249b {} {} sqlite_autoindex_t2249a_1} + } {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.12.3 { # In this case, the +b disables the affinity conflict and allows # the OR optimization to be used again. The result is now an empty # set, the same as in where2-6.9. queryplan { - SELECT * FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello'; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello'; } - } {nosort t2249b {} {} sqlite_autoindex_t2249a_1} + } {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.13 { # The addition of +a on the second term disabled the OR optimization. # But we should still get the same empty-set result as in where2-6.9. queryplan { - SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello'; + SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello'; } - } {nosort t2249b {} t2249a {}} + } {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} } # Variations on the order of terms in a WHERE clause in order # to make sure the OR optimizer can recognize them all. do_test where2-6.20 { queryplan { - SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE x.a=y.a + SELECT x.a, y.a FROM t2249a x CROSS JOIN t2249a y WHERE x.a=y.a } -} {0123 0123 nosort x {} {} sqlite_autoindex_t2249a_1} +} {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1} ifcapable explain&&subquery { # These tests are not run if subquery support is not included in the # build. This is because these tests test the "a = 1 OR a = 2" to @@ -416,19 +464,22 @@ ifcapable explain&&subquery { # do_test where2-6.21 { queryplan { - SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE x.a=y.a OR y.a='hello' + SELECT x.a,y.a FROM t2249a x CROSS JOIN t2249a y + WHERE x.a=y.a OR y.a='hello' } - } {0123 0123 nosort x {} {} sqlite_autoindex_t2249a_1} + } {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1} do_test where2-6.22 { queryplan { - SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE y.a=x.a OR y.a='hello' + SELECT x.a,y.a FROM t2249a x CROSS JOIN t2249a y + WHERE y.a=x.a OR y.a='hello' } - } {0123 0123 nosort x {} {} sqlite_autoindex_t2249a_1} + } {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1} do_test where2-6.23 { queryplan { - SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE y.a='hello' OR x.a=y.a + SELECT x.a,y.a FROM t2249a x CROSS JOIN t2249a y + WHERE y.a='hello' OR x.a=y.a } - } {0123 0123 nosort x {} {} sqlite_autoindex_t2249a_1} + } {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1} } # Unique queries (queries that are guaranteed to return only a single @@ -464,6 +515,8 @@ do_test where2-7.4 { } } {1 2 3 2 3 nosort} +} ;# if {[permutation] != "no_optimization"} + # Ticket #1807. Using IN constrains on multiple columns of # a multi-column index. # @@ -685,5 +738,26 @@ do_test where2-11.4 { } } {4 8 10} +# Verify that the OR clause is used in an outer loop even when +# the OR clause scores slightly better on an inner loop. +if {[permutation] != "no_optimization"} { +do_execsql_test where2-12.1 { + CREATE TABLE t12(x INTEGER PRIMARY KEY, y INT, z CHAR(100)); + CREATE INDEX t12y ON t12(y); + EXPLAIN QUERY PLAN + SELECT a.x, b.x + FROM t12 AS a JOIN t12 AS b ON a.y=b.x + WHERE (b.x=$abc OR b.y=$abc); +} {/.*SEARCH TABLE t12 AS b .*SEARCH TABLE t12 AS b .*/} +} + +# Verify that all necessary OP_OpenRead opcodes occur in the OR optimization. +# +do_execsql_test where2-13.1 { + CREATE TABLE t13(a,b); + CREATE INDEX t13a ON t13(a); + INSERT INTO t13 VALUES(4,5); + SELECT * FROM t13 WHERE (1=2 AND a=3) OR a=4; +} {4 5} finish_test diff --git a/test/where3.test b/test/where3.test index e08f905..c2804b5 100644 --- a/test/where3.test +++ b/test/where3.test @@ -103,12 +103,22 @@ ifcapable explain { } # This procedure executes the SQL. Then it appends -# the ::sqlite_query_plan variable. +# the names of the table and index used # proc queryplan {sql} { set ::sqlite_sort_count 0 set data [execsql $sql] - return [concat $data $::sqlite_query_plan] + set eqp [execsql "EXPLAIN QUERY PLAN $sql"] + # puts eqp=$eqp + foreach {a b c x} $eqp { + if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ + $x all as tab idx]} { + lappend data $tab $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { + lappend data $tab * + } + } + return $data } @@ -144,73 +154,73 @@ do_test where3-2.1 { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND bpk=ax } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.1 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON cx=dpk WHERE cpk=bx AND bpk=ax } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.2 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON cx=dpk WHERE bx=cpk AND bpk=ax } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.3 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON cx=dpk WHERE bx=cpk AND ax=bpk } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.4 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE bx=cpk AND ax=bpk } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.5 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND ax=bpk } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.2 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND apk=bx } -} {tB {} tA * tC * tD *} +} {tB * tA * tC * tD *} do_test where3-2.3 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND apk=bx } -} {tB {} tA * tC * tD *} +} {tB * tA * tC * tD *} do_test where3-2.4 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE apk=cx AND bpk=ax } -} {tC {} tA * tB * tD *} +} {tC * tA * tB * tD *} do_test where3-2.5 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=ax AND bpk=cx } -} {tA {} tC * tB * tD *} +} {tA * tC * tB * tD *} do_test where3-2.6 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE bpk=cx AND apk=bx } -} {tC {} tB * tA * tD *} +} {tC * tB * tA * tD *} do_test where3-2.7 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND apk=cx } -} {tB {} tC * tA * tD *} +} {tB * tC * tA * tD *} # Ticket [13f033c865f878953] # If the outer loop must be a full table scan, do not let ANALYZE trick @@ -221,22 +231,30 @@ do_execsql_test where3-3.0 { CREATE TABLE t301(a INTEGER PRIMARY KEY,b,c); CREATE INDEX t301c ON t301(c); INSERT INTO t301 VALUES(1,2,3); + INSERT INTO t301 VALUES(2,2,3); CREATE TABLE t302(x, y); INSERT INTO t302 VALUES(4,5); ANALYZE; explain query plan SELECT * FROM t302, t301 WHERE t302.x=5 AND t301.a=t302.y; } { - 0 0 0 {SCAN TABLE t302 (~1 rows)} - 0 1 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SCAN TABLE t302} + 0 1 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test where3-3.1 { explain query plan SELECT * FROM t301, t302 WHERE t302.x=5 AND t301.a=t302.y; } { - 0 0 1 {SCAN TABLE t302 (~1 rows)} - 0 1 0 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 1 {SCAN TABLE t302} + 0 1 0 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} } +do_execsql_test where3-3.2 { + SELECT * FROM t301 WHERE c=3 AND a IS NULL; +} {} +do_execsql_test where3-3.3 { + SELECT * FROM t301 WHERE c=3 AND a IS NOT NULL; +} {1 2 3 2 2 3} +if 0 { # Query planner no longer does this # Verify that when there are multiple tables in a join which must be # full table scans that the query planner attempts put the table with # the fewest number of output rows as the outer loop. @@ -248,26 +266,27 @@ do_execsql_test where3-4.0 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t402.z GLOB 'abc*'; } { - 0 0 2 {SCAN TABLE t402 (~500000 rows)} - 0 1 0 {SCAN TABLE t400 (~1000000 rows)} - 0 2 1 {SCAN TABLE t401 (~1000000 rows)} + 0 0 2 {SCAN TABLE t402} + 0 1 0 {SCAN TABLE t400} + 0 2 1 {SCAN TABLE t401} } do_execsql_test where3-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t401.r GLOB 'abc*'; } { - 0 0 1 {SCAN TABLE t401 (~500000 rows)} - 0 1 0 {SCAN TABLE t400 (~1000000 rows)} - 0 2 2 {SCAN TABLE t402 (~1000000 rows)} + 0 0 1 {SCAN TABLE t401} + 0 1 0 {SCAN TABLE t400} + 0 2 2 {SCAN TABLE t402} } do_execsql_test where3-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t400.c GLOB 'abc*'; } { - 0 0 0 {SCAN TABLE t400 (~500000 rows)} - 0 1 1 {SCAN TABLE t401 (~1000000 rows)} - 0 2 2 {SCAN TABLE t402 (~1000000 rows)} + 0 0 0 {SCAN TABLE t400} + 0 1 1 {SCAN TABLE t401} + 0 2 2 {SCAN TABLE t402} } +} ;# endif # Verify that a performance regression encountered by firefox # has been fixed. @@ -298,8 +317,8 @@ do_execsql_test where3-5.0 { AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { - 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) (~10 rows)} - 0 1 1 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} + 0 1 1 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_execsql_test where3-5.1 { @@ -311,8 +330,8 @@ do_execsql_test where3-5.1 { AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { - 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) (~10 rows)} - 0 1 1 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} + 0 1 1 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_execsql_test where3-5.2 { @@ -324,8 +343,8 @@ do_execsql_test where3-5.2 { AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { - 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) (~10 rows)} - 0 1 0 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} + 0 1 0 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_execsql_test where3-5.3 { @@ -337,8 +356,8 @@ do_execsql_test where3-5.3 { AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { - 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) (~10 rows)} - 0 1 0 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} + 0 1 0 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } @@ -424,5 +443,48 @@ foreach predicate { } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} } +do_execsql_test where3-7-setup { + CREATE TABLE t71(x1 INTEGER PRIMARY KEY, y1); + CREATE TABLE t72(x2 INTEGER PRIMARY KEY, y2); + CREATE TABLE t73(x3, y3); + CREATE TABLE t74(x4, y4); + INSERT INTO t71 VALUES(123,234); + INSERT INTO t72 VALUES(234,345); + INSERT INTO t73 VALUES(123,234); + INSERT INTO t74 VALUES(234,345); + INSERT INTO t74 VALUES(234,678); +} {} +foreach disabled_opt {none omit-noop-join all} { + optimization_control db all 1 + optimization_control db $disabled_opt 0 + do_execsql_test where3-7.$disabled_opt.1 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1; + } {123} + do_execsql_test where3-7.$disabled_opt.2 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1 WHERE y2 IS NULL; + } {} + do_execsql_test where3-7.$disabled_opt.3 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1 WHERE y2 IS NOT NULL; + } {123} + do_execsql_test where3-7.$disabled_opt.4 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1 AND y2 IS NULL; + } {123} + do_execsql_test where3-7.$disabled_opt.5 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1 AND y2 IS NOT NULL; + } {123} + do_execsql_test where3-7.$disabled_opt.6 { + SELECT x3 FROM t73 LEFT JOIN t72 ON x2=y3; + } {123} + do_execsql_test where3-7.$disabled_opt.7 { + SELECT DISTINCT x3 FROM t73 LEFT JOIN t72 ON x2=y3; + } {123} + do_execsql_test where3-7.$disabled_opt.8 { + SELECT x3 FROM t73 LEFT JOIN t74 ON x4=y3; + } {123 123} + do_execsql_test where3-7.$disabled_opt.9 { + SELECT DISTINCT x3 FROM t73 LEFT JOIN t74 ON x4=y3; + } {123} +} + finish_test diff --git a/test/where4.test b/test/where4.test index 280eb5f..a26e9ad 100644 --- a/test/where4.test +++ b/test/where4.test @@ -71,7 +71,7 @@ do_test where4-1.5 { } {1 2} do_test where4-1.6 { count {SELECT rowid FROM t1 WHERE w=1 AND x<9} -} {1 3} +} {1 2} do_test where4-1.7 { count {SELECT rowid FROM t1 WHERE w=1 AND x IS NULL AND y=3} } {2 2} @@ -98,7 +98,7 @@ do_test where4-1.14 { } {7 2} do_test where4-1.15 { count {SELECT rowid FROM t1 WHERE w IS NULL AND x IS NULL AND y<0} -} {2} +} {1} do_test where4-1.16 { count {SELECT rowid FROM t1 WHERE w IS NULL AND x IS NULL AND y>=0} } {1} diff --git a/test/where7.test b/test/where7.test index b6cd7cc..5032c69 100644 --- a/test/where7.test +++ b/test/where7.test @@ -23303,7 +23303,7 @@ do_test where7-2.1001.2 { # # The test case that follows is code from an actual # application with identifiers change and unused columns -# remove. +# removed. # do_execsql_test where7-3.1 { CREATE TABLE t301 ( @@ -23332,16 +23332,16 @@ do_execsql_test where7-3.1 { EXPLAIN QUERY PLAN SELECT t302.c1 - FROM t302 JOIN t301 ON t302.c8 = t301.c8 + FROM t302 JOIN t301 ON t302.c8 = +t301.c8 WHERE t302.c2 = 19571 AND t302.c3 > 1287603136 AND (t301.c4 = 1407449685622784 OR t301.c8 = 1407424651264000) ORDER BY t302.c5 LIMIT 200; } { - 0 0 1 {SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?) (~10 rows)} - 0 0 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} - 0 1 0 {SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?) (~2 rows)} + 0 0 1 {SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?)} + 0 0 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} + 0 1 0 {SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } diff --git a/test/where8.test b/test/where8.test index 9b6014e..139251a 100644 --- a/test/where8.test +++ b/test/where8.test @@ -12,7 +12,6 @@ # is testing of where.c. More specifically, the focus is the optimization # of WHERE clauses that feature the OR operator. # -# $Id: where8.test,v 1.9 2009/07/31 06:14:52 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -88,13 +87,13 @@ do_test where8-1.8 { do_test where8-1.9 { execsql_status2 { SELECT c FROM t1 WHERE a >= 9 OR b <= 'eight' } -} {IX X VIII 0 0 6} +} {IX X VIII 0 0 7} do_test where8-1.10 { execsql_status2 { SELECT c FROM t1 WHERE (a >= 9 AND c != 'X') OR b <= 'eight' } -} {IX VIII 0 0 6} +} {IX VIII 0 0 7} do_test where8-1.11 { execsql_status2 { @@ -211,9 +210,10 @@ do_test where8-3.4 { do_test where8-3.5 { execsql_status { - SELECT a, d FROM t1, t2 WHERE (a = 2 OR a = 3) AND (d = a OR e = 'sixteen') + SELECT a, d FROM t1, t2 WHERE (a = 2 OR a = 3) AND (d = +a OR e = 'sixteen') + ORDER BY +a, +d; } -} {2 2 2 4 3 3 3 4 0 0} +} {2 2 2 4 3 3 3 4 0 1} do_test where8-3.6 { # The first part of the WHERE clause in this query, (a=2 OR a=3) is @@ -222,7 +222,7 @@ do_test where8-3.6 { execsql_status { SELECT a, d FROM t1, t2 - WHERE (a = 2 OR a = 3) AND (d = a OR e = 'sixteen') + WHERE (a = 2 OR a = 3) AND (d = +a OR e = 'sixteen') ORDER BY t1.rowid } } {2 2 2 4 3 3 3 4 0 1} @@ -233,7 +233,7 @@ do_test where8-3.7 { WHERE a = 2 AND (d = a OR e = 'sixteen') ORDER BY t1.rowid } -} {2 2 2 4 0 0} +} {/2 2 2 4 0 [01]/} do_test where8-3.8 { execsql_status { SELECT a, d @@ -268,7 +268,7 @@ do_test where8-3.12 { execsql_status { SELECT a, d FROM t1, t2 WHERE (a=d OR b=e) AND +a<5 ORDER BY a } -} {1 1 2 2 3 3 4 2 4 4 0 0} +} {1 1 2 2 3 3 4 2 4 4 9 0} do_test where8-3.13 { execsql_status { SELECT a, d FROM t1, t2 WHERE (a=d OR b=e) AND +a<5 @@ -748,4 +748,13 @@ do_test where8-5.3 { } } {1 {}} +# The OR optimization and WITHOUT ROWID +# +do_execsql_test where8-6.1 { + CREATE TABLE t600(a PRIMARY KEY, b) WITHOUT rowid; + CREATE INDEX t600b ON t600(b); + INSERT INTO t600 VALUES('state','screen'),('exact','dolphin'),('green','mercury'); + SELECT a, b, '|' FROM t600 WHERE a=='state' OR b='mercury' ORDER BY +a; +} {green mercury | state screen |} + finish_test diff --git a/test/where9.test b/test/where9.test index 1e94fdf..d073074 100644 --- a/test/where9.test +++ b/test/where9.test @@ -362,9 +362,9 @@ ifcapable explain { SELECT t2.a FROM t1, t2 WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f) } { - 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} - 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?) (~2 rows)} - 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} + 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?)} + 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)} } do_execsql_test where9-3.2 { EXPLAIN QUERY PLAN @@ -372,9 +372,9 @@ ifcapable explain { FROM t1 LEFT JOIN t2 ON (t1.c+1=t2.c AND t1.d=t2.d) OR (t1.f||'x')=t2.f WHERE t1.a=80 } { - 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} - 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?) (~2 rows)} - 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} + 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?)} + 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)} } } @@ -420,7 +420,7 @@ do_test where9-4.5 { AND (c=31031 OR d IS NULL) ORDER BY +a } -} {1 {cannot use index: t1b}} +} {1 {no query solution}} do_test where9-4.6 { count_steps { SELECT a FROM t1 NOT INDEXED @@ -436,7 +436,7 @@ do_test where9-4.7 { AND (c=31031 OR d IS NULL) ORDER BY +a } -} {1 {cannot use index: t1c}} +} {1 {no query solution}} do_test where9-4.8 { catchsql { SELECT a FROM t1 INDEXED BY t1d @@ -444,7 +444,7 @@ do_test where9-4.8 { AND (c=31031 OR d IS NULL) ORDER BY +a } -} {1 {cannot use index: t1d}} +} {1 {no query solution}} ifcapable explain { # The (c=31031 OR d IS NULL) clause is preferred over b>1000 because @@ -453,8 +453,8 @@ ifcapable explain { do_execsql_test where9-5.1 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c=31031 OR d IS NULL) } { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?) (~3 rows)} - 0 0 0 {SEARCH TABLE t1 USING INDEX t1d (d=?) (~3 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1d (d=?)} } # In contrast, b=1000 is preferred over any OR-clause. @@ -462,7 +462,7 @@ ifcapable explain { do_execsql_test where9-5.2 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b=1000 AND (c=31031 OR d IS NULL) } { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~5 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)} } # Likewise, inequalities in an AND are preferred over inequalities in @@ -471,7 +471,7 @@ ifcapable explain { do_execsql_test where9-5.3 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c>=31031 OR d IS NULL) } { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>?) (~125000 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>?)} } } @@ -768,20 +768,62 @@ do_test where9-6.7.4 { do_test where9-6.8.1 { catchsql { DELETE FROM t1 INDEXED BY t1b - WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {1 {cannot use index: t1b}} +} {1 {no query solution}} do_test where9-6.8.2 { catchsql { UPDATE t1 INDEXED BY t1b SET a=a+100 - WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {1 {cannot use index: t1b}} +} {1 {no query solution}} +set solution_possible 0 +ifcapable stat4||stat3 { + if {[permutation] != "no_optimization"} { set solution_possible 1 } +} +if $solution_possible { + # When STAT3 is enabled, the "b NOT NULL" terms get translated + # into b>NULL, which can be satified by the index t1b. It is a very + # expensive way to do the query, but it works, and so a solution is possible. + do_test where9-6.8.3-stat4 { + catchsql { + UPDATE t1 INDEXED BY t1b SET a=a+100 + WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } + } {0 {}} + do_test where9-6.8.4-stat4 { + catchsql { + DELETE FROM t1 INDEXED BY t1b + WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } + } {0 {}} +} else { + do_test where9-6.8.3 { + catchsql { + UPDATE t1 INDEXED BY t1b SET a=a+100 + WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } + } {1 {no query solution}} + do_test where9-6.8.4 { + catchsql { + DELETE FROM t1 INDEXED BY t1b + WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } + } {1 {no query solution}} +} ############################################################################ # Test cases where terms inside an OR series are combined with AND terms # external to the OR clause. In other words, cases where @@ -814,6 +856,11 @@ do_test where9-7.0 { INSERT INTO t6 SELECT * FROM t5; ANALYZE t5; } + ifcapable stat3 { + sqlite3 db2 test.db + db2 eval { DROP TABLE IF EXISTS sqlite_stat3 } + db2 close + } } {} do_test where9-7.1.1 { count_steps { @@ -914,4 +961,28 @@ do_test where9-9.1 { } } {1 2 3 4 8 9} +# Fix for ticket [bc878246eafe0f52c519e29049b2fe4a99491b27] +# Incorrect result when OR is used in a join to the right of a LEFT JOIN +# +do_test where9-10.1 { + db eval { + CREATE TABLE t101 (id INTEGER PRIMARY KEY); + INSERT INTO t101 VALUES (1); + SELECT * FROM t101 AS t0 + LEFT JOIN t101 AS t1 ON t1.id BETWEEN 10 AND 20 + JOIN t101 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id)); + } +} {1 {} 1} +do_test where9-10.2 { + db eval { + CREATE TABLE t102 (id TEXT UNIQUE NOT NULL); + INSERT INTO t102 VALUES ('1'); + SELECT * FROM t102 AS t0 + LEFT JOIN t102 AS t1 ON t1.id GLOB 'abc%' + JOIN t102 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id)); + } +} {1 {} 1} + + + finish_test diff --git a/test/whereA.test b/test/whereA.test index 5d0aca5..78826b1 100644 --- a/test/whereA.test +++ b/test/whereA.test @@ -68,6 +68,12 @@ do_test whereA-1.7 { SELECT * FROM t1; } } {3 4.53 {} 2 hello world 1 2 3} +do_execsql_test whereA-1.8 { + SELECT * FROM t1 WHERE b=2 AND a IS NULL; +} {} +do_execsql_test whereA-1.9 { + SELECT * FROM t1 WHERE b=2 AND a IS NOT NULL; +} {1 2 3} do_test whereA-2.1 { db eval { diff --git a/test/whereC.test b/test/whereC.test index 9fa1bba..bd7fe9a 100644 --- a/test/whereC.test +++ b/test/whereC.test @@ -67,4 +67,3 @@ foreach {tn sql res} { finish_test - diff --git a/test/whereD.test b/test/whereD.test index 9ac5a68..db99304 100644 --- a/test/whereD.test +++ b/test/whereD.test @@ -186,4 +186,90 @@ do_test 4.3 { } } {1 2 3 3 6 9 4 5 6 {} {} {}} +# Ticket [bc1aea7b725f276177] +# Incorrect result on LEFT JOIN with OR constraints and an ORDER BY clause. +# +do_execsql_test 4.4 { + CREATE TABLE t44(a INTEGER, b INTEGER); + INSERT INTO t44 VALUES(1,2); + INSERT INTO t44 VALUES(3,4); + SELECT * + FROM t44 AS x + LEFT JOIN (SELECT a AS c, b AS d FROM t44) AS y ON a=c + WHERE d=4 OR d IS NULL; +} {3 4 3 4} +do_execsql_test 4.5 { + SELECT * + FROM t44 AS x + LEFT JOIN (SELECT a AS c, b AS d FROM t44) AS y ON a=c + WHERE d=4 OR d IS NULL + ORDER BY a; +} {3 4 3 4} +do_execsql_test 4.6 { + CREATE TABLE t46(c INTEGER, d INTEGER); + INSERT INTO t46 SELECT a, b FROM t44; + SELECT * FROM t44 LEFT JOIN t46 ON a=c + WHERE d=4 OR d IS NULL; +} {3 4 3 4} +do_execsql_test 4.7 { + SELECT * FROM t44 LEFT JOIN t46 ON a=c + WHERE d=4 OR d IS NULL + ORDER BY a; +} {3 4 3 4} + +# Verify fix of a bug reported on the mailing list by Peter Reid +# +do_execsql_test 5.1 { + DROP TABLE IF EXISTS t; + CREATE TABLE t(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17); + CREATE INDEX tc0 ON t(c0); + CREATE INDEX tc1 ON t(c1); + CREATE INDEX tc2 ON t(c2); + CREATE INDEX tc3 ON t(c3); + CREATE INDEX tc4 ON t(c4); + CREATE INDEX tc5 ON t(c5); + CREATE INDEX tc6 ON t(c6); + CREATE INDEX tc7 ON t(c7); + CREATE INDEX tc8 ON t(c8); + CREATE INDEX tc9 ON t(c9); + CREATE INDEX tc10 ON t(c10); + CREATE INDEX tc11 ON t(c11); + CREATE INDEX tc12 ON t(c12); + CREATE INDEX tc13 ON t(c13); + CREATE INDEX tc14 ON t(c14); + CREATE INDEX tc15 ON t(c15); + CREATE INDEX tc16 ON t(c16); + CREATE INDEX tc17 ON t(c17); + + INSERT INTO t(c0, c16) VALUES (1,1); + + SELECT * FROM t WHERE + c0=1 or c1=1 or c2=1 or c3=1 or + c4=1 or c5=1 or c6=1 or c7=1 or + c8=1 or c9=1 or c10=1 or c11=1 or + c12=1 or c13=1 or c14=1 or c15=1 or + c16=1 or c17=1; +} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {}} +do_execsql_test 5.2 { + DELETE FROM t; + INSERT INTO t(c0,c17) VALUES(1,1); + SELECT * FROM t WHERE + c0=1 or c1=1 or c2=1 or c3=1 or + c4=1 or c5=1 or c6=1 or c7=1 or + c8=1 or c9=1 or c10=1 or c11=1 or + c12=1 or c13=1 or c14=1 or c15=1 or + c16=1 or c17=1; +} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1} +do_execsql_test 5.3 { + DELETE FROM t; + INSERT INTO t(c0,c15) VALUES(1,1); + SELECT * FROM t WHERE + c0=1 or c1=1 or c2=1 or c3=1 or + c4=1 or c5=1 or c6=1 or c7=1 or + c8=1 or c9=1 or c10=1 or c11=1 or + c12=1 or c13=1 or c14=1 or c15=1 or + c16=1 or c17=1; +} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {} {}} + + finish_test diff --git a/test/whereE.test b/test/whereE.test index e686a46..a6b8f48 100644 --- a/test/whereE.test +++ b/test/whereE.test @@ -47,16 +47,16 @@ do_execsql_test 1.1 { CREATE UNIQUE INDEX t2zx ON t2(z,x); EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} do_execsql_test 1.2 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} do_execsql_test 1.3 { ANALYZE; EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} do_execsql_test 1.4 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} finish_test diff --git a/test/whereF.test b/test/whereF.test index 57bdbee..b9580bb 100644 --- a/test/whereF.test +++ b/test/whereF.test @@ -46,7 +46,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -set testprefix x +set testprefix whereF do_execsql_test 1.0 { PRAGMA automatic_index = 0; @@ -63,7 +63,7 @@ foreach {tn sql} { } { do_test 1.$tn { db eval "EXPLAIN QUERY PLAN $sql" - } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} + } {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/} } do_execsql_test 2.0 { @@ -84,7 +84,7 @@ foreach {tn sql} { } { do_test 2.$tn { db eval "EXPLAIN QUERY PLAN $sql" - } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} + } {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/} } do_execsql_test 3.0 { @@ -109,7 +109,14 @@ foreach {tn sql} { } { do_test 3.$tn { db eval "EXPLAIN QUERY PLAN $sql" - } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} + } {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/} } +do_execsql_test 4.0 { + CREATE TABLE t4(a,b,c,d,e, PRIMARY KEY(a,b,c)); + CREATE INDEX t4adc ON t4(a,d,c); + CREATE UNIQUE INDEX t4aebc ON t4(a,e,b,c); + EXPLAIN QUERY PLAN SELECT rowid FROM t4 WHERE a=? AND b=?; +} {/a=. AND b=./} + finish_test diff --git a/test/whereG.test b/test/whereG.test new file mode 100644 index 0000000..c2c54db --- /dev/null +++ b/test/whereG.test @@ -0,0 +1,233 @@ +# 2013-09-05 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Test cases for query planning decisions and the likely(), unlikely(), and +# likelihood() functions. + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix whereG + +do_execsql_test whereG-1.0 { + CREATE TABLE composer( + cid INTEGER PRIMARY KEY, + cname TEXT + ); + CREATE TABLE album( + aid INTEGER PRIMARY KEY, + aname TEXT + ); + CREATE TABLE track( + tid INTEGER PRIMARY KEY, + cid INTEGER REFERENCES composer, + aid INTEGER REFERENCES album, + title TEXT + ); + CREATE INDEX track_i1 ON track(cid); + CREATE INDEX track_i2 ON track(aid); + INSERT INTO composer VALUES(1, 'W. A. Mozart'); + INSERT INTO composer VALUES(2, 'Beethoven'); + INSERT INTO composer VALUES(3, 'Thomas Tallis'); + INSERT INTO composer VALUES(4, 'Joseph Hayden'); + INSERT INTO composer VALUES(5, 'Thomas Weelkes'); + INSERT INTO composer VALUES(6, 'J. S. Bach'); + INSERT INTO composer VALUES(7, 'Orlando Gibbons'); + INSERT INTO composer VALUES(8, 'Josquin des Prés'); + INSERT INTO composer VALUES(9, 'Byrd'); + INSERT INTO composer VALUES(10, 'Francis Poulenc'); + INSERT INTO composer VALUES(11, 'Mendelsshon'); + INSERT INTO composer VALUES(12, 'Zoltán Kodály'); + INSERT INTO composer VALUES(13, 'Handel'); + INSERT INTO album VALUES(100, 'Kodály: Missa Brevis'); + INSERT INTO album VALUES(101, 'Messiah'); + INSERT INTO album VALUES(102, 'Missa Brevis in D-, K.65'); + INSERT INTO album VALUES(103, 'The complete English anthems'); + INSERT INTO album VALUES(104, 'Mass in B Minor, BWV 232'); + INSERT INTO track VALUES(10005, 12, 100, 'Sanctus'); + INSERT INTO track VALUES(10007, 12, 100, 'Agnus Dei'); + INSERT INTO track VALUES(10115, 13, 101, 'Surely He Hath Borne Our Griefs'); + INSERT INTO track VALUES(10129, 13, 101, 'Since By Man Came Death'); + INSERT INTO track VALUES(10206, 1, 102, 'Agnus Dei'); + INSERT INTO track VALUES(10301, 3, 103, 'If Ye Love Me'); + INSERT INTO track VALUES(10402, 6, 104, 'Domine Deus'); + INSERT INTO track VALUES(10403, 6, 104, 'Qui tollis'); +} {} +do_eqp_test whereG-1.1 { + SELECT DISTINCT aname + FROM album, composer, track + WHERE unlikely(cname LIKE '%bach%') + AND composer.cid=track.cid + AND album.aid=track.aid; +} {/.*composer.*track.*album.*/} +do_execsql_test whereG-1.2 { + SELECT DISTINCT aname + FROM album, composer, track + WHERE unlikely(cname LIKE '%bach%') + AND composer.cid=track.cid + AND album.aid=track.aid; +} {{Mass in B Minor, BWV 232}} + +do_eqp_test whereG-1.3 { + SELECT DISTINCT aname + FROM album, composer, track + WHERE likelihood(cname LIKE '%bach%', 0.5) + AND composer.cid=track.cid + AND album.aid=track.aid; +} {/.*track.*composer.*album.*/} +do_execsql_test whereG-1.4 { + SELECT DISTINCT aname + FROM album, composer, track + WHERE likelihood(cname LIKE '%bach%', 0.5) + AND composer.cid=track.cid + AND album.aid=track.aid; +} {{Mass in B Minor, BWV 232}} + +do_eqp_test whereG-1.5 { + SELECT DISTINCT aname + FROM album, composer, track + WHERE cname LIKE '%bach%' + AND composer.cid=track.cid + AND album.aid=track.aid; +} {/.*track.*(composer.*album|album.*composer).*/} +do_execsql_test whereG-1.6 { + SELECT DISTINCT aname + FROM album, composer, track + WHERE cname LIKE '%bach%' + AND composer.cid=track.cid + AND album.aid=track.aid; +} {{Mass in B Minor, BWV 232}} + +do_eqp_test whereG-1.7 { + SELECT DISTINCT aname + FROM album, composer, track + WHERE cname LIKE '%bach%' + AND unlikely(composer.cid=track.cid) + AND unlikely(album.aid=track.aid); +} {/.*track.*(composer.*album|album.*composer).*/} +do_execsql_test whereG-1.8 { + SELECT DISTINCT aname + FROM album, composer, track + WHERE cname LIKE '%bach%' + AND unlikely(composer.cid=track.cid) + AND unlikely(album.aid=track.aid); +} {{Mass in B Minor, BWV 232}} + +do_test whereG-2.1 { + catchsql { + SELECT DISTINCT aname + FROM album, composer, track + WHERE likelihood(cname LIKE '%bach%', -0.01) + AND composer.cid=track.cid + AND album.aid=track.aid; + } +} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}} +do_test whereG-2.2 { + catchsql { + SELECT DISTINCT aname + FROM album, composer, track + WHERE likelihood(cname LIKE '%bach%', 1.01) + AND composer.cid=track.cid + AND album.aid=track.aid; + } +} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}} +do_test whereG-2.3 { + catchsql { + SELECT DISTINCT aname + FROM album, composer, track + WHERE likelihood(cname LIKE '%bach%', track.cid) + AND composer.cid=track.cid + AND album.aid=track.aid; + } +} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}} + +# Commuting a term of the WHERE clause should not change the query plan +# +do_execsql_test whereG-3.0 { + CREATE TABLE a(a1 PRIMARY KEY, a2); + CREATE TABLE b(b1 PRIMARY KEY, b2); +} {} +do_eqp_test whereG-3.1 { + SELECT * FROM a, b WHERE b1=a1 AND a2=5; +} {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} +do_eqp_test whereG-3.2 { + SELECT * FROM a, b WHERE a1=b1 AND a2=5; +} {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} +do_eqp_test whereG-3.3 { + SELECT * FROM a, b WHERE a2=5 AND b1=a1; +} {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} +do_eqp_test whereG-3.4 { + SELECT * FROM a, b WHERE a2=5 AND a1=b1; +} {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} + +# Ticket [1e64dd782a126f48d78c43a664844a41d0e6334e]: +# Incorrect result in a nested GROUP BY/DISTINCT due to the use of an OP_SCopy +# where an OP_Copy was needed. +# +do_execsql_test whereG-4.0 { + CREATE TABLE t4(x); + INSERT INTO t4 VALUES('right'),('wrong'); + SELECT DISTINCT x + FROM (SELECT x FROM t4 GROUP BY x) + WHERE x='right' + ORDER BY x; +} {right} + +#------------------------------------------------------------------------- +# Test that likelihood() specifications on indexed terms are taken into +# account by various forms of loops. +# +# 5.1.*: open ended range scans +# 5.2.*: skip-scans +# +reset_db + +do_execsql_test 5.1 { + CREATE TABLE t1(a, b, c); + CREATE INDEX i1 ON t1(a, b); +} +do_eqp_test 5.1.2 { + SELECT * FROM t1 WHERE a>? +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} +do_eqp_test 5.1.3 { + SELECT * FROM t1 WHERE likelihood(a>?, 0.9) +} {0 0 0 {SCAN TABLE t1}} +do_eqp_test 5.1.4 { + SELECT * FROM t1 WHERE likely(a>?) +} {0 0 0 {SCAN TABLE t1}} + +do_test 5.2 { + for {set i 0} {$i < 100} {incr i} { + execsql { INSERT INTO t1 VALUES('abc', $i, $i); } + } + execsql { INSERT INTO t1 SELECT 'def', b, c FROM t1; } + execsql { ANALYZE } +} {} +do_eqp_test 5.2.2 { + SELECT * FROM t1 WHERE likelihood(b>?, 0.01) +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (ANY(a) AND b>?)}} +do_eqp_test 5.2.3 { + SELECT * FROM t1 WHERE likelihood(b>?, 0.9) +} {0 0 0 {SCAN TABLE t1}} +do_eqp_test 5.2.4 { + SELECT * FROM t1 WHERE likely(b>?) +} {0 0 0 {SCAN TABLE t1}} + +do_eqp_test 5.3.1 { + SELECT * FROM t1 WHERE a=? +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} +do_eqp_test 5.3.2 { + SELECT * FROM t1 WHERE likelihood(a=?, 0.9) +} {0 0 0 {SCAN TABLE t1}} +do_eqp_test 5.3.3 { + SELECT * FROM t1 WHERE likely(a=?) +} {0 0 0 {SCAN TABLE t1}} + +finish_test diff --git a/test/whereH.test b/test/whereH.test new file mode 100644 index 0000000..c252fe1 --- /dev/null +++ b/test/whereH.test @@ -0,0 +1,139 @@ +# 2014-03-31 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Test cases for query planning decisions where one candidate index +# covers a proper superset of the WHERE clause terms of another +# candidate index. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test whereH-1.1 { + CREATE TABLE t1(a,b,c,d); + CREATE INDEX t1abc ON t1(a,b,c); + CREATE INDEX t1bc ON t1(b,c); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c; +} {/INDEX t1abc /} +do_execsql_test whereH-1.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-2.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d); + CREATE INDEX t1bc ON t1(b,c); + CREATE INDEX t1abc ON t1(a,b,c); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c; +} {/INDEX t1abc /} +do_execsql_test whereH-2.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-3.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1cd ON t1(c,d); + CREATE INDEX t1bcd ON t1(b,c,d); + CREATE INDEX t1abcd ON t1(a,b,c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-3.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-4.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1cd ON t1(c,d); + CREATE INDEX t1abcd ON t1(a,b,c,d); + CREATE INDEX t1bcd ON t1(b,c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-4.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-5.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1bcd ON t1(b,c,d); + CREATE INDEX t1cd ON t1(c,d); + CREATE INDEX t1abcd ON t1(a,b,c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-5.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-6.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1bcd ON t1(b,c,d); + CREATE INDEX t1abcd ON t1(a,b,c,d); + CREATE INDEX t1cd ON t1(c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-6.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-7.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1abcd ON t1(a,b,c,d); + CREATE INDEX t1bcd ON t1(b,c,d); + CREATE INDEX t1cd ON t1(c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-7.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-8.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1abcd ON t1(a,b,c,d); + CREATE INDEX t1cd ON t1(c,d); + CREATE INDEX t1bcd ON t1(b,c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-8.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + + + +finish_test diff --git a/test/whereI.test b/test/whereI.test new file mode 100644 index 0000000..452e7f8 --- /dev/null +++ b/test/whereI.test @@ -0,0 +1,92 @@ +# 2014-03-31 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# The focus of this file is testing the OR optimization on WITHOUT ROWID +# tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix whereI + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, c, PRIMARY KEY(a)) WITHOUT ROWID; + INSERT INTO t1 VALUES(1, 'a', 'z'); + INSERT INTO t1 VALUES(2, 'b', 'y'); + INSERT INTO t1 VALUES(3, 'c', 'x'); + INSERT INTO t1 VALUES(4, 'd', 'w'); + CREATE INDEX i1 ON t1(b); + CREATE INDEX i2 ON t1(c); +} + +do_eqp_test 1.1 { + SELECT a FROM t1 WHERE b='b' OR c='x' +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b=?)} + 0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)} +} + +do_execsql_test 1.2 { + SELECT a FROM t1 WHERE b='b' OR c='x' +} {2 3} + +do_execsql_test 1.3 { + SELECT a FROM t1 WHERE b='a' OR c='z' +} {1} + +#---------------------------------------------------------------------- +# Try that again, this time with non integer PRIMARY KEY values. +# +do_execsql_test 2.0 { + CREATE TABLE t2(a, b, c, PRIMARY KEY(a)) WITHOUT ROWID; + INSERT INTO t2 VALUES('i', 'a', 'z'); + INSERT INTO t2 VALUES('ii', 'b', 'y'); + INSERT INTO t2 VALUES('iii', 'c', 'x'); + INSERT INTO t2 VALUES('iv', 'd', 'w'); + CREATE INDEX i3 ON t2(b); + CREATE INDEX i4 ON t2(c); +} + +do_eqp_test 2.1 { + SELECT a FROM t2 WHERE b='b' OR c='x' +} { + 0 0 0 {SEARCH TABLE t2 USING INDEX i3 (b=?)} + 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)} +} + +do_execsql_test 2.2 { + SELECT a FROM t2 WHERE b='b' OR c='x' +} {ii iii} + +do_execsql_test 2.3 { + SELECT a FROM t2 WHERE b='a' OR c='z' +} {i} + +#---------------------------------------------------------------------- +# On a table with a multi-column PK. +# +do_execsql_test 3.0 { + CREATE TABLE t3(a, b, c, d, PRIMARY KEY(c, b)) WITHOUT ROWID; + + INSERT INTO t3 VALUES('f', 1, 1, 'o'); + INSERT INTO t3 VALUES('o', 2, 1, 't'); + INSERT INTO t3 VALUES('t', 1, 2, 't'); + INSERT INTO t3 VALUES('t', 2, 2, 'f'); + + CREATE INDEX t3i1 ON t3(d); + CREATE INDEX t3i2 ON t3(a); + + SELECT c||'.'||b FROM t3 WHERE a='t' OR d='t' +} { + 2.1 2.2 1.2 +} + +finish_test + diff --git a/test/whereJ.test b/test/whereJ.test new file mode 100644 index 0000000..5209f16 --- /dev/null +++ b/test/whereJ.test @@ -0,0 +1,375 @@ +# 2014-06-06 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements regression tests for a complex +# query planning case. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix whereJ + +ifcapable !stat4 { + finish_test + return +} + +do_execsql_test whereJ-1.0 { + CREATE TABLE tx1 ( + est, + cid, + sid, + fid, + aid, + edate, + rstat, + ftype, + cx, + fyear, + fp, + acode, + a1, + curx, + tdate, + gstat, + trgtpx, + effdate, + adate, + ytime, + mstat + ); + CREATE INDEX ix0 on tx1(a1,curx,aid,cid,sid,ftype,fp,fyear DESC,edate DESC,fid); + CREATE INDEX ix1 on tx1(a1,curx,aid,ftype,fp,fyear DESC,fid,edate DESC,cid,sid); + CREATE INDEX ix2 on tx1(a1,curx,cid,sid,ftype,fp,fyear DESC,edate DESC,aid,fid); + CREATE INDEX ix3 on tx1(a1,curx,fid,ftype,fp,fyear DESC,cid,sid,aid,edate DESC); + CREATE INDEX ix4 on tx1(a1,curx,ftype,cid,sid,aid,edate DESC,fid,fp,fyear DESC); + CREATE INDEX ix5 on tx1(a1,curx,ftype,aid,fid,cid,sid,edate DESC,fp,fyear DESC); + CREATE INDEX ix6 on tx1(ftype,fp,fyear DESC,cid,sid,edate DESC,a1,fid,aid,curx,est,rstat,cx,acode,tdate,gstat,trgtpx,effdate,adate,ytime,mstat); + CREATE INDEX ix7 on tx1(cid,a1,curx,sid,ftype,est,fid,aid,edate,rstat,cx,fyear,fp,acode,tdate,gstat,trgtpx,effdate,adate,ytime,mstat); + CREATE INDEX ix8 on tx1(cid,sid,edate DESC,aid,est); + CREATE INDEX ix9 on tx1(aid,edate DESC,a1,curx); +} {} +do_execsql_test whereJ-1.1 { + ANALYZE sqlite_master; + DELETE FROM sqlite_stat1; + DELETE FROM sqlite_stat4; + INSERT INTO sqlite_stat1 VALUES('tx1','ix9','11680827 289 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix8','11680827 286 250 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix7','11680827 286 194 98 88 83 18 7 6 2 2 2 2 2 2 2 2 2 2 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix6','11680827 5840414 5840414 5840414 240 212 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix5','11680827 5840414 2920207 1668690 114 90 8 8 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix4','11680827 5840414 2920207 1668690 92 83 9 2 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix3','11680827 5840414 2920207 2048 1835 1835 1835 12 11 8 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix2','11680827 5840414 2920207 98 88 83 83 83 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix1','11680827 5840414 2920207 117 114 114 114 90 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix0','11680827 5840414 2920207 117 9 9 9 9 9 2 2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6736 21 21 21 1','29210 29404 29404 29404 29424','44 12184 13020 13079 29424',X'06030409080416C1150133512800B01FCA'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6658 24 21 21 1','452220 453273 453276 453276 453296','622 226258 235279 236774 453296',X'06030409080416F34501332ADC00AA1BD3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','820 2 2 2 1','1297771 1297869 1297869 1297869 1297869','1964 681724 711020 715822 1297869',X'06030409080317875501332C6C55AF4D'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','26985 2216 2216 2216 1','1797607 1797782 1797782 1797782 1799997','3162 970307 1008879 1016089 1799997',X'0603040809041A08040132401A0099A334'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','10434 19 17 17 1','2118117 2120403 2120405 2120405 2120421','3815 1136110 1181459 1190207 2120421',X'0603040908041AD36901332CD000861A2F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','437 1 1 1 1','2595414 2595739 2595739 2595739 2595739','5005 1409452 1464066 1475163 2595739',X'0603040808031CE7FD01317FD46BFBCC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','12619 38 38 38 1','2595957 2600212 2600212 2600212 2600249','5007 1410347 1464961 1476068 2600249',X'0603040808041CE87E01328F61008CE96A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','7534 23 18 18 1','3329985 3334890 3334895 3334895 3334912','6901 1834013 1902216 1917268 3334912',X'060304090804244E1901328F59008CAA39'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','5693 1 1 1 1','3891665 3893609 3893609 3893609 3893609','8357 2164400 2245393 2263185 3893609',X'0603040808043063B70132B66800A28A43'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','44405 2588 2223 1527 1','4220255 4221633 4221998 4222694 4224220','9221 2354858 2441973 2461511 4224220',X'0603040909043377630133517A00B0DE4F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6883 32 28 28 1','4423918 4429926 4429930 4429930 4429957','9690 2452276 2543443 2563995 4429957',X'06030409080434F46801328F5C008CC3DA'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6974 27 26 26 1','5048404 5051129 5051130 5051130 5051155','11703 2817010 2920184 2944013 5051155',X'0603040908043C1C5C0132DEA5009F7473'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','476 2 2 2 1','5191322 5191479 5191479 5191479 5191479','12242 2901130 3006663 3031222 5191479',X'0603040908033DC6080132DEA478849A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','627 4 4 4 1','6488823 6489349 6489349 6489349 6489349','16423 3644815 3778857 3809866 6489349',X'0603040808035AA00E0131F4AE342150'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','145 2 2 1 1','7787091 7787218 7787218 7787219 7787219','20223 4343720 4510110 4547961 7787219',X'0603040809037254890132189C703706'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','20 1 1 1 1','9085074 9085089 9085089 9085089 9085089','25315 5033102 5230788 5275692 9085089',X'06040408080300EAE6CA01326657620652'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','229621 6135 5934 5934 1','9507353 9572696 9572696 9572696 9576801','27189 5255584 5463962 5511784 9576801',X'06040408080300F2FA440132DF1A7D1A60'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6376 24 22 22 1','10381524 10382938 10382940 10382940 10382959','30519 5581705 5804515 5856651 10382959',X'06040409080400F9DBF3013305AC00A688A4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','7761 45 9 9 1','10569039 10572476 10572512 10572512 10572520','31455 5661599 5888691 5941811 10572520',X'06040409080400FB31560132DDD800A05DF5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','8382 37 37 37 1','10866664 10867565 10867565 10867565 10867601','33475 5809193 6042611 6097741 10867601',X'06040409080400FFA4A701332A0E00A93957'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','76136 4099 3018 3018 1','11283107 11308143 11309224 11309224 11312241','37001 6022861 6264510 6322923 11312241',X'060404090804010B0A5C0133517200B0E8E0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','23472 2188 2188 2181 1','11365285 11380281 11380281 11380288 11382468','37055 6026680 6268909 6327509 11382468',X'060404080904010B3C6701332B2E00AA4374'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','59591 4087 4073 4 1','11415316 11448759 11448773 11452842 11452845','37350 6040743 6283483 6342389 11452845',X'060404090904010BFA810133512800B010AE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','43891 3029 3021 4 1','11598477 11622881 11622889 11625906 11625909','39110 6107644 6353109 6413914 11625909',X'0604040909040113B9960133512800B01235'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7340 4977 19 1 1 1','206533 206533 208739 208757 208757 208757','125 164 111403 207397 207399 208757',X'070308040407030187840132B54B0101A0D1401C0000000000004C87E5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','8877 8788 45 1 1 1','1221375 1221375 1224509 1224553 1224553 1224553','931 1117 679933 1216705 1216722 1224553',X'07030804040703018D3F0133023D010B9B67401C0000000000007A99EF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7204 7204 39 1 1 1','1240162 1240162 1242572 1242610 1242610 1242610','942 1131 688420 1234655 1234672 1242610',X'07030804040703018D4F0132DB820105D324401C0000000000007EC569'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','9608 9608 44 1 1 1','1264939 1264939 1266529 1266572 1266572 1266572','952 1145 699518 1258423 1258440 1266572',X'07030804040704018D61013305B9010D3CEB406E8000000000000081E17A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','6636 6636 1 1 1 1','1294580 1294580 1297869 1297869 1297869 1297869','964 1159 713121 1289522 1289540 1297869',X'07030804030704018D7801328F693482A2403400000000000000A26728'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7822 6629 26 1 1 1','2375708 2375708 2381333 2381358 2381358 2381358','3423 3833 1371902 2366527 2366559 2381358',X'0703080403070301B1F501317F16403B7B403F00000000000060D67A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','1403 1303 5 1 1 1','2594767 2594767 2595737 2595739 2595739 2595739','3914 4427 1512042 2580073 2580114 2595739',X'0703080403070301B6480131CC18558082407120000000000029CC12'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7901 6067 26 1 1 1','3424107 3424107 3425939 3425964 3425964 3425964','5872 6630 2032411 3406550 3406594 3425964',X'0703080404070401C3F90132B7A100FDCC04403E00000000000000A014CE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7483 6161 22 1 1 1','3549446 3549446 3555223 3555244 3555244 3555244','5932 6752 2099309 3535259 3535304 3555244',X'0703080403070301C4490131573F4104F8403400000000000067FD1E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','12076 8263 37 1 1 1','3558079 3558079 3560036 3560072 3560072 3560072','5935 6758 2101989 3540078 3540123 3560072',X'0703080404070301C44E0132DD0901076DA9404200000000000076F994'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','1123 1113 1 1 1 1','3892913 3892913 3893609 3893609 3893609 3893609','6594 7611 2305483 3871711 3871770 3893609',X'0703080403070301CA280131CA1C215083401C00000000000071F6B2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','9344 7315 41 1 1 1','4213510 4213510 4219434 4219474 4219474 4219474','7200 8390 2503024 4196141 4196204 4219474',X'0703080404070301CE8C01317DE800FE4E8B4034000000000000458317'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','8062 3291 1 1 1 1','5037060 5037060 5040350 5040350 5040350 5040350','10201 11915 3045602 5012912 5012997 5040350',X'070308040307030213B20130B83A16DF86403600000000000028F8CD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','9125 2926 1 1 1 1','5046490 5052665 5055590 5055590 5055590 5055590','10203 11926 3055524 5028097 5028182 5055590',X'070302040307030213B5232A013107F01745AF40330000000000002B57DE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','591 591 1 1 1 1','5190991 5190991 5191479 5191479 5191479 5191479','10649 12426 3145181 5163206 5163296 5191479',X'070308040307030244AD0131315217C1CD401C00000000000003BC32'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7381 4689 1 1 1 1','6112248 6112248 6116936 6116936 6116936 6116936','13780 16308 3748958 6083681 6083797 6116936',X'0703080403070402A9D1013108B531A21C401C0000000000000092F5C6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7569 7381 28 1 1 1','6280084 6280084 6281842 6281869 6281869 6281869','14559 17217 3856803 6247722 6247841 6281869',X'0703080404070302C14C0132DBF101044CC7401C00000000000074FB16'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','8289 7047 28 1 1 1','6290764 6290764 6296854 6296881 6296881 6296881','14569 17229 3863206 6262658 6262777 6296881',X'0703080403070302C16401317CC348B670401C0000000000006824BB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','2209 2209 1 1 1 1','6489075 6489075 6489349 6489349 6489349 6489349','15377 18147 3986912 6454194 6454318 6489349',X'0703080403070402EA5901332A656C6F5E401C00000000000000AE7C03'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7381 6799 1 1 1 1','7314420 7314420 7321218 7321218 7321218 7321218','18403 21722 4532963 7281695 7281847 7321218',X'07030804030703049EE501310667176DC940438000000000005ED2B5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7163 7001 31 1 1 1','7652849 7652849 7658600 7658630 7658630 7658630','19462 22956 4750159 7617449 7617608 7658630',X'070308040407030503EB01317DEF010ADD3F402800000000000061C3EF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','1433 1433 2 1 1 1','7785842 7785842 7787219 7787219 7787219 7787219','20001 23575 4834605 7745315 7745477 7787219',X'07030804030703055010013156D81B11AC404380000000000004A313'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','2247 2247 1 1 1 1','9083272 9083272 9085089 9085089 9085089 9085089','24940 29143 5668423 9036693 9036887 9085089',X'070308040307031A620A01323EEB5CE39C406FE000000000006F8177'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','107 107 5 1 1 1','10382912 10382912 10382957 10382959 10382959 10382959','31251 36297 6541362 10329764 10330008 10382959',X'0704080403070400955501013350516AA9D0406060000000000000884648'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7340 4770 4527 3331 3331 970 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','206533 206533 206533 206533 206533 206596 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565','125 202 402 512 560 6209 20696 25885 206260 206260 206260 206260 206260 206260 206260 206260 206260 206260 206260 206260 206260 207565',X'1703080808080704030408030808010308070808080803018784401C000000000000024FD353493F8801317E4700FFFF0F00FFFFC0F869E0000000002642C5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','8877 4669 71 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','1221375 1225583 1230181 1230249 1230249 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251','931 1504 2992 3495 3751 39629 120561 147424 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1230251',X'1703090902080704030408090808010108070404040804018D3F03E8405680000000000000822B981EB823013351F00F0C4086E00000000000013351F0013351F053870D7500B22A8C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7204 4801 193 193 4 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','1240162 1240162 1244770 1244770 1244959 1244961 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962','942 1520 3024 3531 3791 40098 122274 149540 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1244962',X'1703080908010703030408030808010308070408040803018D4F07406FE000000000000602CF16DE05013303C300FFFF0300FFFFC0F869E000000000013303C3008000004BD756'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','9608 6098 5910 5910 5910 2149 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','1264939 1264939 1264939 1264939 1264939 1265217 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365','952 1536 3055 3576 3841 40616 124132 151876 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1267365',X'1703080808080704030408090808010101070404040803018D61401C0000000000000131374D1726AB0132DD780F0C0540390000000000000132DD780132DD784E2789C6190CA9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','6636 4411 4237 4237 4237 33 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1','1294580 1294580 1294580 1294580 1294580 1297842 1297862 1297862 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869','964 1557 3097 3622 3888 41246 126538 154868 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1297869',X'1703080808080703030408090808010308070808080803018D7840420000000000007332F1227B5901321AF80800FFFF40260000000000006D0CEB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7822 4817 260 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','2375708 2375708 2380265 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524','3423 5117 10120 11184 11775 86237 242937 294878 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2380524',X'170308090308070304040803080801030807040408080401B1F501831C405C40000000000077646800EAD44C0132697000FFFF0300FFFFC0F869E0000000000132696F0132696F0094935E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','1403 1022 82 74 74 55 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','2594767 2594767 2595707 2595707 2595707 2595708 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739','3914 5817 11518 12879 13613 98100 278304 342850 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2595739',X'170308090808070303040803080801030807080808080301B648405C400000000000038EAC243F770131A6F700FFFF0E00FFFFC0F869E0000000005C8664'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7901 5298 291 55 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','3424107 3424107 3429114 3429350 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404','5872 8944 17727 19769 20846 145206 401995 498360 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3429404',X'170308090201070404040803080801030807040808080401C3F9232807405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E000000000013329460083157B'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7483 5407 230 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','3549446 3549446 3554623 3554845 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852','5932 9041 17921 20139 21264 149060 417718 520064 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3554852',X'170308090201070404040803080801030807040808080401C449232807405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E000000000013329460083162A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','12076 8365 7981 5546 5546 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','3558079 3558079 3558079 3558079 3558079 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624','5935 9046 17930 20154 21279 149235 418443 521109 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3563624',X'170308080808070303040803080801030107040408080301C44E4074300000000000029EB13BB98E01328EFE00FFFF0E00FFFF0AC0F869E00000000001328F0001328F0071D802'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','1123 916 875 875 875 93 22 22 1 1 1 1 1 1 1 1 1 1 1 1 1 1','3892913 3892913 3892913 3892913 3892913 3893531 3893602 3893602 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609','6594 10057 19942 22653 23964 165533 468498 587524 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3893609',X'170308080808070403040802080801030107040404080301CA28403F00000000000000832DC71933330132DB8800FC0F00FFFF054050C000000000000132DB870132DB8A4D5E35A2107205'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','9344 6359 6022 9 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','4213510 4213510 4213510 4219523 4219523 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531','7200 11025 21872 25036 26543 181203 517345 652858 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4219531',X'170308080308070303040803080801030807080808080301CE8C0186A0403F00000000000002C2142F19870131554100FFFF0F00FFFFC0F869E0000000000687F7'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','8062 4993 241 53 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','5037060 5037060 5041812 5042000 5042051 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052','10201 15484 30736 35196 37326 231854 654010 829510 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5042052',X'17030809020107030404080308080103080704080808030213B2245407406FE0000000000002C0AA00F6ABA101332A7E00FFFF0300FFFFC0F869E00000000001332A7E5287C0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','9125 5761 264 5 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','5046490 5046490 5051987 5052246 5052246 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250','10203 15488 30744 35230 37365 232178 654964 830718 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5052250',X'17030809030807030304080308080103080708080808030213B501831F406FE00000000000029E627136F901328DD500FFFF0300FFFFC0F869E000000000290DD6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','591 591 566 566 566 27 18 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1','5190991 5190991 5190991 5190991 5190991 5191461 5191464 5191474 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479','10649 16115 31973 36593 38793 239550 673441 853755 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5191479',X'17030808080807030404080108080101080708080808040244AD4045800000000000029E6200EAE8740132690D0A0F0C402E00000000000000941EAF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7381 3728 83 16 16 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','6112248 6115901 6119546 6119613 6119613 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628','13780 20707 41067 47538 50438 296473 834203 1056686 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6119628',X'170309090208070304040809080801010807040404080402A9D12328407360000000000002172300EABCFF0133517F0F0C404AA6665E02EA960133517F01335239538BC5C1008B5EC9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7569 5785 274 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','6280084 6280084 6285595 6285867 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868','14559 21811 43240 50020 53057 307264 862871 1092992 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6285868',X'170308090301070404040803080801030807040808080302C14C01832707405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E000000000013329461E5109'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','8289 5734 266 33 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','6290764 6290764 6296232 6296465 6296495 6296495 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497','14569 21827 43272 50056 53096 307563 864043 1094585 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6296497',X'170308090201070404040803080801030807040808080402C164232807405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E0000000000133294600A90415'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','2209 1450 1369 1369 1369 597 13 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1','6489075 6489075 6489075 6489075 6489075 6489139 6489344 6489344 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349','15377 22998 45584 52641 55837 319564 895653 1134252 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6489349',X'170308080808070303040802080801030807040404080302EA59401C0000000000000D4B201AD8B30132DF0400FC0600FFFF40180000000000000132DF040132DF054EBA338714FBBA'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7381 5446 171 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','7314420 7314420 7319695 7319855 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865','18403 27319 54152 62541 66337 369851 1032180 1306261 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7319865',X'1703080902010703030408030808010308070408080804049EE503E907405C400000000000029EC32E97BE0133061F00FFFF0300FFFFC0F869E0000000000133061F00A9ECEF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7163 4782 209 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','7652849 7652849 7657422 7657626 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630','19462 28830 57147 65962 69945 388539 1084446 1372423 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7657630',X'17030809020107040404080308080103080704080808040503EB03EA07405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E0000000000133294600831554'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','1433 582 571 571 571 15 15 15 1 1 1 1 1 1 1 1 1 1 1 1 1 1','7785842 7786693 7786693 7786693 7786693 7787208 7787208 7787208 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219','20001 29582 58632 67649 71736 396840 1107204 1400830 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7787219',X'1703090808080703040408090808010108070404040804055010406E80000000000001C7A600FC429201332D890F0C402C00000000000001332D890133505352D7248A008775D8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','2247 682 657 657 657 117 45 45 1 1 1 1 1 1 1 1 1 1 1 1 1 1','9083272 9084837 9084837 9084837 9084837 9085088 9085088 9085088 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089','24940 36384 72113 82665 87632 474987 1318830 1664527 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9085089',X'17030908080807030304080208080103010704040408031A620A403E00000000000001C3D332CF850132DE9D00FC0200FFFF054050E000000000000132DE9D0132DE9D4E8C092E790553'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','107 77 69 69 69 11 5 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1','10382912 10382942 10382942 10382942 10382942 10382952 10382956 10382956 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959','31251 45639 90416 102896 109225 567280 1544395 1943661 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10382959',X'170409080808070303040809080801010807040404080300955501403E000000000000029E686E250B01332D220F0C402E00000000000001332D220133504E52CFCF4F21CD7F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7337 4975 19 19 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 206462 206462 210789 210789 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807','0 0 0 125 164 112407 128579 207456 209489 209490 209490 209490 209490 209490 209490 209490 209490 209490 209490 209490 209490 210807',X'170808080308040804030807080301030807080808080301878401317F26024FD3531E2DAF404200000000000000FFFF0200FFFFC0F869E0000000002642C4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 8874 8785 45 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 1221012 1221012 1224145 1224165 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189','0 0 0 931 1117 679896 773861 1207582 1216653 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1224189',X'1708080803080409040408070809010308070404040803018D3F0133023D01940C420106B14D40420000000000000F00FFFF4070E000000000000133023D0133023D4F2053654AE525'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7200 7200 39 15 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 1239793 1239793 1242199 1242223 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237','0 0 0 942 1131 688381 783660 1225441 1234602 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1242237',X'1708080803080409040308070809010301070404040804018D4F0132DB820113FAB92F19C5401C0000000000000F00FFFF0F403A0000000000000132DB820132DB824D542A4F009B5C72'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 9606 9606 44 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 1264560 1264560 1266149 1266168 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192','0 0 0 952 1145 699479 796008 1249062 1258369 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1266192',X'1708080803080409040308070809010101070404040803018D61013305B9017CDF4916F8B140280000000000000F0C0A403600000000000001330557013305B9507EA8DD212E79'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 6635 6635 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 1294199 1294199 1297868 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869','0 0 0 964 1159 713241 812408 1280435 1289849 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1297869',X'1708080803080409030308070803010308070808080803018D78013267DC0EF747387106403F00000000000000FFFF0F00FFFFC0F869E00000000006B968'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7815 6624 26 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 2374939 2374939 2380559 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584','0 0 0 3423 3833 1371803 1539928 2350493 2366415 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2380584',X'170808080308040903030807080301030807080808080301B1F501317F160DDEA51C46AB405280000000000000FFFF0F00FFFFC0F869E0000000006ADDA9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 3595 3459 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 2595336 2595336 2595734 2595737 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739','0 0 0 3918 4433 1512586 1693312 2557025 2580917 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2595739',X'170808080308040903030807080101010107040404080301B64F01332ACC029E833D19084028000000000000320F0C054074A0000000000001332A0901332ACC518A316F1F30D6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7894 6061 26 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 3422592 3422592 3424418 3424434 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443','0 0 0 5872 6630 2032185 2267240 3366727 3406294 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3424443',X'170808080308040904030807080101030807040404080401C3F90132B7A100D6FD7F6CE97F4070500000000000100F00FFFF40560000000000000132B7310132DB2D4D3F72D9009AE8EE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7479 6158 22 22 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 3547845 3547845 3553619 3553619 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640','0 0 0 5932 6752 2099067 2343370 3491679 3534981 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3553640',X'170808080308040804030807080301030807080808080301C4490131573F008E7AC03077E0403E00000000000000FFFF0F00FFFFC0F869E00000000065B45A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 12068 8257 37 17 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 3556474 3556474 3558426 3558446 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462','0 0 0 5935 6758 2101744 2346448 3496404 3539797 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3558462',X'170808080308040904030807080201010107040404080301C44E0132DD09016891C11788EB404200000000000000FC0F0C0F400199999999999A0132DD090132DD094DE5DCE3763299'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 1510 1497 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 3892149 3892149 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609','0 0 0 6596 7614 2306358 2572095 3823194 3873232 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3893609',X'170808080308040803030807080301030807080808080301CA2E01312E3A038EE6257265400000000000000000FFFF0600FFFFC0F869E00000000032518F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 9341 7313 41 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 4211282 4211282 4217204 4217243 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244','0 0 0 7200 8390 2502650 2792131 4139620 4195704 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4217244',X'170808080308040903030807080301030807080808080301CE8C01317DE8029E9D3B6D23403E00000000000000FFFF0F00FFFFC0F869E00000000008EF7D'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 8055 3290 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 5033936 5033936 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225','0 0 0 10201 11915 3045026 3383481 4941323 5012256 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5037225',X'17080808030804090303080708030803080708080808030213B20130B83A018A7516DF86403600000000000000FFFF00FFFFC0F869E00000000028F8CD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 9117 2923 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 5043358 5049528 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450','0 0 0 10203 11926 3054947 3394812 4956408 5027439 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5052450',X'17080808030204080303080708030103080708080808030213B5232A013107F00217231745AF403300000000000000FFFF0200FFFFC0F869E0000000002B57DE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 333 333 4 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 5191271 5191271 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479','0 0 0 10672 12452 3147059 3494842 5093162 5165710 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5191479',X'17080808030804080303080708030103080708080808030244F00131CB4201C1C917188E403F00000000000000FFFF0800FFFFC0F869E00000000001C5CB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7374 4684 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 6107894 6107894 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577','0 0 0 13780 16308 3748117 4153600 5995776 6082692 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6112577',X'170808080308040803030807080301030807080808080402A9D1013108B5029E6831A21C401C00000000000000FFFF0200FFFFC0F869E0000000000092F5C6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7562 7376 28 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 6275521 6275521 6277274 6277291 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301','0 0 0 14559 17217 3855913 4271255 6156622 6246677 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6277301',X'170808080308040904030807080201030107040404080302C14C0132DBF100832DC739FF53403F00000000000000FC0F00FFFF05402C0000000000000132DBF10132DBF34D89B7AA1114CB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 8282 7043 28 28 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 6286191 6286191 6292277 6292277 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304','0 0 0 14569 17229 3862314 4278722 6171137 6261611 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6292304',X'170808080308040804030807080301030807080808080302C16401317CC301B5AA4A1AB270405680000000000000FFFF0F00FFFFC0F869E00000000048FD4C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 3101 3101 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 6486495 6486495 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349','0 0 0 15379 18149 3988504 4417216 6363796 6457879 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6489349',X'170808080308040803030807080301030807080808080302EA6601317F7301C3EB17C4CE401C00000000000000FFFF0F00FFFFC0F869E000000000398198'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7379 6798 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 7308682 7308682 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479','0 0 0 18403 21722 4531809 5008068 7172304 7280343 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7315479',X'1708080803080408040308070803010308070808080803049EE501310667008390D0176DC9404380000000000000FFFF0500FFFFC0F869E0000000005ED2B5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 211 211 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 7787150 7787150 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219','0 0 0 20027 23602 4837427 5341824 7634169 7750020 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7787219',X'17080808030804080303080708090103080704040808030550B30132B73501A79C17C3D840340000000000000F00FFFF40140000000000000132B6D00132B7400D1DB9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 26 26 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 9085083 9085083 9085088 9085088 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089','0 0 0 24964 29171 5671673 6246216 8904392 9042441 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9085089',X'17080808030804080303080708030103080708080808031AA25C0131CA197A6D831B1D84401C00000000000000FFFF0F00FFFFC0F869E00000000071E307'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 1261 1261 9 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 10381872 10381872 10382956 10382956 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959','0 0 0 31297 36344 6545140 7198586 10180602 10336983 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10382959',X'17080808040804080303080708010101080708080808030095A4C401321BB603010141073C401C000000000000080F0C40308000000000007E55BE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','12287 12287 12287 17 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','11668540 11668540 11668540 11672111 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127','1 1 1 43128 49243 7431284 8170740 11452355 11624787 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11672127',X'1701080803020408040409070803010308070408040804070267C127130133041E00AB540900E64074405C40000000000000FFFF0300FFFFC0F869E0000000000133041E0080000000A3EE16'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 24157 24157 29 29 1 1 1 1','0 0 0 1236590 1236590 1251799 1251799 1251827 1251827 1251827 1251827','0 0 0 3120 4771 71527 72755 1238782 1238782 1238782 1251827',X'0C08080803040308040808031A080400FF5594029BB30131CD372B1368'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 1209 1209 129 129 1 1 1 1','0 0 0 1296873 1296873 1297744 1297744 1297869 1297869 1297869 1297869','0 0 0 3203 4902 74577 75831 1284645 1284645 1284645 1297869',X'0C08080803030308040808041A215F04C9D901B0A30131066F0087162A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 12129 9261 428 428 1 1 1 1','0 0 0 1790076 1790076 1790076 1790076 1790503 1790503 1790503 1790503','0 0 0 4938 7561 108783 110860 1774402 1774402 1774402 1790503',X'0C08080803030308040808031CE87E029E6B018700013219C1373BA8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 273 273 5 5 1 1 1 1','0 0 0 2595625 2595625 2595738 2595738 2595739 2595739 2595739 2595739','0 0 0 7863 12132 166423 169877 2575172 2575172 2575172 2595739',X'0C08080803030308040808042F020502DA0E02C73A0133049700A711F8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 7735 7735 29 29 1 1 1 1','0 0 0 2924165 2924165 2929754 2929754 2929782 2929782 2929782 2929782','0 0 0 9123 14045 191316 195293 2907742 2907742 2907742 2929782',X'0C080808030403080408080333776300FF559475928D013329435A824F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 360 229 27 27 1 1 1 1','0 0 0 3893374 3893505 3893605 3893605 3893609 3893609 3893609 3893609','0 0 0 13912 21124 273265 278784 3866425 3866425 3866425 3893609',X'0C08080803030308040808044717710E070B01E88F0131A5B80098D0A5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 683 671 32 32 1 1 1 1','0 0 0 5191447 5191459 5191477 5191477 5191479 5191479 5191479 5191479','0 0 0 20361 30776 381171 389104 5158962 5158962 5158962 5191479',X'0C08080803030308040808037370D10F00290188450132B537354C5E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 213354 213354 113 113 1 1 1 1','0 0 0 6102233 6102233 6155183 6155183 6155295 6155295 6155295 6155295','0 0 0 26812 39489 472780 483115 6119281 6119281 6119281 6155295',X'0C080808040403080408080300F2FA4400FF5594019B6D01324067714AE8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 3675 3675 241 241 1 1 1 1','0 0 0 6486701 6486701 6489287 6489287 6489349 6489349 6489349 6489349','0 0 0 28380 41383 502486 513750 6452691 6452691 6452691 6489349',X'0C080808040304080408080300F6ABAC6C967D009F84B60132DBDD155A2A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 24063 24063 38 38 1 1 1 1','0 0 0 7080911 7080911 7102380 7102380 7102417 7102417 7102417 7102417','0 0 0 35724 49844 582928 595393 7065320 7065320 7065320 7102417',X'0C0808080404040804080803010B0A5C00FF559400CCD3EE0133294559DDCD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 20284 20284 38 38 1 1 1 1','0 0 0 7107237 7107237 7126606 7126606 7126643 7126643 7126643 7126643','0 0 0 35764 49885 586473 599030 7089546 7089546 7089546 7126643',X'0C0808080404040804080803010B3C6700FF55940114CE73013329432225CC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 630326 618063 11855 11855 3 1 1 1 1 1','0 7173953 7173953 7665258 7665258 7672559 7672561 7672561 7672561 7672561 7672561','0 1 2 64320 91213 1077048 1100563 7630436 7630436 7630436 7672561',X'0C080908040403020408080400F2FA4400FF559405DD0A23280132DD75009F3468'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 630326 618063 4 4 1 1 1 1 1 1','0 7173953 7173953 7787218 7787218 7787219 7787219 7787219 7787219 7787219 7787219','0 1 2 74034 102405 1189484 1215034 7745001 7745001 7745001 7787219',X'0C0809080403040804080803010DDABE0368B700FEBFF60133068F22D1E5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 630326 12263 1433 1433 1 1 1 1 1 1','0 7173953 7792016 7797877 7797877 7799309 7799309 7799309 7799309 7799309 7799309','0 1 3 76213 104626 1201397 1227113 7757087 7757087 7757087 7799309',X'0C08090104040408040808030700F2FA4400FF559401C3969E013329461E5052'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 8657 8657 605 605 1 1 1 1','7804279 7804279 7804279 8360485 8360485 8364643 8364643 8365247 8365247 8365247 8365247','1 2 4 77865 106290 1217527 1243460 8321843 8321843 8321843 8365247',X'0C09080803030308040808031AD369021FFC0DC36E01328E2F3D9128'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 33421 33421 57 26 1 1 1 1','7804279 7804279 7804279 8873934 8873934 8891008 8891039 8891064 8891064 8891064 8891064','1 2 4 78914 107340 1231432 1257622 8846644 8846644 8846644 8891064',X'0C090808030403020408080433776300FF55940CE166232801332A1800836DFB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 2182 2182 94 94 1 1 1 1','7804279 7804279 7804279 9083187 9083187 9085006 9085006 9085089 9085089 9085089 9085089','1 2 4 79307 107733 1237174 1263453 9040316 9040316 9040316 9085089',X'0C09080803030308040808033AC92C021FFC04AF670132B5FC38DBD0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 6023 6023 50 50 1 1 1 1','7804279 7804279 7804279 9393480 9393480 9395815 9395815 9395864 9395864 9395864 9395864','1 2 4 79973 108402 1245294 1271679 9350536 9350536 9350536 9395864',X'0C09080803030308040808034CDD9A7E1C2301C30D0132908703CC11'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 79 79 6 6 1 1 1 1','7804279 7804279 7804279 10382946 10382946 10382956 10382956 10382959 10382959 10382959 10382959','1 2 4 82501 110947 1276304 1303221 10336296 10336296 10336296 10382959',X'0C090808040303080408080400E9A10A0CC31602A47201332C6C00ABCD60'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 8251 8251 280 280 1 1 1 1','7804279 7804279 7804279 11067468 11067468 11072690 11072690 11072969 11072969 11072969 11072969','1 2 4 85529 113989 1307763 1335183 11025935 11025935 11025935 11072969',X'0C090808040404080408080300FFA4A7008A66AD0089DBDD0132B5FF6AE2B8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 44772 44772 58 58 1 1 1 1','7804279 7804279 7804279 11268036 11268036 11269261 11269261 11269318 11269318 11269318 11269318','1 2 4 87132 115597 1321101 1348736 11222284 11222284 11222284 11269318',X'0C0908080404030804080804010B0A5C00FF5594018ACD0133294300B0E291'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 53775 53775 37 19 1 1 1 1','7804279 7804279 7804279 11330929 11330929 11355027 11355045 11355063 11355063 11355063 11355063','1 2 4 87335 115800 1327560 1355328 11308029 11308029 11308029 11355063',X'0C0908080404030204080803010BFA8100FF5594026C24232801332B2E1F8BB5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 39430 39430 39 39 1 1 1 1','7804279 7804279 7804279 11458789 11458789 11476757 11476757 11476795 11476795 11476795 11476795','1 2 4 88502 116970 1340484 1368500 11429761 11429761 11429761 11476795',X'0C09080804040308040808030113B99600FF559402F6AF01332B2E1F8A54'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 157757 157736 5317 5317 1 1 1 1 1 1','7804279 11523070 11523070 11652823 11652823 11658139 11658139 11658139 11658139 11658139 11658139','1 3 5 100045 128561 1480184 1510648 11611105 11611105 11611105 11658139',X'0C0909080404040204080803010BFA8100FF559402594CCB2328013351E85B0F5D'); +} {} +do_execsql_test whereJ-1.3 { + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4748 4629 308 1 1 1 1 1','0 0 0 634880 634880 639119 639426 639426 639426 639426 639426','0 0 0 779 907 26900 633919 633920 633920 633920 639426',X'0C0808080308040403080803018C4A00F450A80132671F029EAC271DA5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4608 4608 246 1 1 1 1 1','0 0 0 752580 752580 755578 755823 755823 755823 755823 755823','0 0 0 936 1089 31876 749384 749385 749385 749385 755823',X'0C0808080308030403080804018D4F347FD20131547D018A7500936FE2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4776 4776 240 1 1 1 1 1','0 0 0 762070 762070 764545 764784 764784 764784 764784 764784','0 0 0 940 1097 32187 758274 758275 758275 758275 764784',X'0C0808080308030403080804018D562E0EAB0131A68F029E9300994D36'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5910 5910 257 1 1 1 1 1','0 0 0 771353 771353 772646 772902 772902 772902 772902 772902','0 0 0 946 1103 32460 766333 766334 766334 766334 772902',X'0C0808080308030404080803018D611726F40130E13C00822B980302A0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 1834 1834 46 1 1 1 1 1','0 0 0 1296866 1296866 1297832 1297869 1297869 1297869 1297869 1297869','0 0 0 2621 2842 56932 1287063 1287064 1287064 1287064 1297869',X'0C080808030803040308080301A6E33010BC01317F2005516E3932DB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5007 3959 317 1 1 1 1 1','0 0 0 2152400 2152400 2153781 2154097 2154097 2154097 2154097 2154097','0 0 0 5683 6304 111431 2139450 2139457 2139457 2139457 2154097',X'0C080808030803040308080301C3F91E114001315549029F74635F36'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4768 4609 397 1 1 1 1 1','0 0 0 2200466 2200466 2200700 2201096 2201096 2201096 2201096 2201096','0 0 0 5714 6370 114266 2186220 2186227 2186227 2186227 2201096',X'0C080808030803040308080401C42217887E01312D72036D5B009AF3F8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5177 4669 264 1 1 1 1 1','0 0 0 2234078 2234078 2235865 2236128 2236128 2236128 2236128 2236128','0 0 0 5743 6422 116499 2221108 2221115 2221115 2221115 2236128',X'0C080808030803040308080401C4491EF49D013155450D4B200091BFB3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 7981 5546 272 1 1 1 1 1','0 0 0 2239923 2239923 2242583 2242854 2242854 2242854 2242854 2242854','0 0 0 5746 6428 116800 2227775 2227782 2227782 2227782 2242854',X'0C080808030803040308080301C44E2EFF35013109E67764687E36D6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 351 336 15 1 1 1 1 1','0 0 0 2595725 2595725 2595725 2595739 2595739 2595739 2595739 2595739','0 0 0 6747 7717 144364 2578697 2578708 2578708 2578708 2595739',X'0C080808030803040308080401CCC91782C20131CC1902D7C0008E7A4F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 6022 4942 304 1 1 1 1 1','0 0 0 2648510 2648510 2648849 2649152 2649152 2649152 2649152 2649152','0 0 0 6934 7959 149030 2631886 2631900 2631900 2631900 2649152',X'0C080808030803040308080301CE8C17887E01312D6E036D5B424939'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4752 1965 5 1 1 1 1 1','0 0 0 3161780 3161780 3163740 3163744 3163744 3163744 3163744 3163744','0 0 0 9707 11219 194477 3143873 3143896 3143896 3143896 3163744',X'0C08080803080404030808030213B20116290C01332B9D0270102494C2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5497 1880 3 1 1 1 1 1','0 0 0 3167643 3167643 3169520 3169522 3169522 3169522 3169522 3169522','0 0 0 9709 11226 194760 3149632 3149655 3149655 3149655 3169522',X'0C08080803080404040808030213B5010B0A5C0133294500FF55941DCA72'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 2185 2126 134 1 1 1 1 1','0 0 0 3891669 3891669 3893607 3893609 3893609 3893609 3893609 3893609','0 0 0 13596 15952 257364 3869701 3869733 3869733 3869733 3893609',X'0C080808030804040308080302BD5F01010F13013350517B8BF356D913'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5511 5355 345 1 1 1 1 1','0 0 0 3931849 3931849 3931954 3932298 3932298 3932298 3932298 3932298','0 0 0 13793 16188 260160 3908172 3908206 3908206 3908206 3932298',X'0C080808030803040308080402C14C17887E01312D75036D5B009AF4B1'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5468 5115 310 1 1 1 1 1','0 0 0 3939090 3939090 3939894 3940203 3940203 3940203 3940203 3940203','0 0 0 13803 16200 260571 3916034 3916068 3916068 3916068 3940203',X'0C080808030803040308080302C164191E7F0131A4FC0606F30CE25A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5275 4792 252 1 1 1 1 1','0 0 0 4590216 4590216 4591340 4591591 4591591 4591591 4591591 4591591','0 0 0 17456 20455 315887 4563939 4563981 4563981 4563981 4591591',X'0C0808080308030403080804049EE51EB67B01317C5204C9D900AE08CD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 339 339 20 1 1 1 1 1','0 0 0 5191257 5191257 5191475 5191479 5191479 5191479 5191479 5191479','0 0 0 20754 24230 366257 5160652 5160701 5160701 5160701 5191479',X'0C08080803080404030808030CEE9300E50D8D013242BE018A755F6BC3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 13 13 1 1 1 1 1 1','0 0 0 6489337 6489337 6489349 6489349 6489349 6489349 6489349 6489349','0 0 0 29449 33987 481632 6453309 6453378 6453378 6453378 6489349',X'0C08080804080304030808030091B3AB600E9801323F54029F7403EF0C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 630326 618063 10 9 1 1 1 1 1 1','0 7173953 7173953 7787217 7787217 7787219 7787219 7787219 7787219 7787219 7787219','0 1 2 74978 85458 1107555 7744920 7744997 7744997 7744997 7787219',X'0C0809080408030403080804014F459B48960801332ADC01C7A600AA1BA3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 630326 12263 17 1 1 1 1 1 1 1','0 7173953 7792016 7795570 7795586 7795586 7795586 7795586 7795586 7795586 7795586','0 1 3 78329 89057 1115864 7753287 7753364 7753364 7753364 7795586',X'0C0809010302040404080804070267C1271300E640740133041E00AB540900A3EE16'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','3876548 3718791 3718791 397 397 46 1 1 1 1 1','7804279 7804279 7804279 9084892 9084892 9085088 9085089 9085089 9085089 9085089 9085089','1 2 4 87584 99143 1159195 9040539 9040616 9040616 9040616 9085089',X'0C090808030804040308080301CBAF00E5C288013351810C390F26671E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','3876548 3718791 3718791 141 141 20 1 1 1 1 1','7804279 7804279 7804279 10382921 10382921 10382951 10382959 10382959 10382959 10382959 10382959','1 2 4 95054 107437 1210217 10336699 10336776 10336776 10336776 10382959',X'0C09080803080304030808030DB5C14114E301332A7E018A751F17C1'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','3876548 157757 157736 83 16 1 1 1 1 1 1','7804279 11523070 11523070 11587733 11587800 11587815 11587815 11587815 11587815 11587815 11587815','1 3 5 112412 126326 1332792 11540704 11540781 11540781 11540781 11587815',X'0C090908030204040308080402A9D12328010B92880133517F029E9D008B5B23'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 213279 213279 213279 213279 376 212 101 1 1','0 0 12394 12394 12394 12394 18421 18421 18421 18424 18424','0 0 3 3 3 3 810 1027 1949 18324 18424',X'0C0808030808080308030403018A75018788178574013265FC611E2A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 86515 86515 86515 86515 377 377 377 1 1','0 0 271240 271240 271240 271240 274521 274521 274521 274780 274780','0 0 8 8 8 8 9766 10762 19602 273178 274780',X'0C080803080808030803040401A79C01886F174AEF0132678B00A4AEFF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 193482 193482 193482 193482 444 444 444 1 1','0 0 542802 542802 542802 542802 575453 575453 575453 575505 575505','0 0 27 27 27 27 24310 25597 43165 571774 575505',X'0C080803080808030803040401C3EB018CCE55312F013305B700AF487C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 126108 126108 126108 126108 200 200 28 1 1','0 0 747801 747801 747801 747801 762121 762121 762293 762320 762320','0 0 33 33 33 33 30770 32410 56629 757315 762320',X'0C080803080808030803040301C7A6018A9D6AB1100131F17D04364A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 149712 149712 149712 149712 216 216 5 1 1','0 0 1107747 1107747 1107747 1107747 1147090 1147090 1147301 1147305 1147305','0 0 98 98 98 98 51603 53785 94043 1139967 1147305',X'0C080803080808030803040302172301B84D2E828501317B95651924'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 87289 87289 87289 87289 27 27 12 1 1','0 0 1257751 1257751 1257751 1257751 1297850 1297850 1297865 1297869 1297869','0 0 100 100 100 100 57625 60123 107069 1289807 1297869',X'0C0808030808080308040403021FFC02554D00E643C7013242692A9BBC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 192597 192597 192597 192597 291 291 3 1 1','0 0 1464077 1464077 1464077 1464077 1512946 1512946 1513234 1513236 1513236','0 0 134 134 134 134 67476 70262 123260 1502886 1513236',X'0C0808030808080308040404029E6201B94000F8341701330419008B74DA'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 196917 196917 196917 196917 326 326 12 1 1','0 0 1677739 1677739 1677739 1677739 1797333 1797333 1797647 1797658 1797658','0 0 136 136 136 136 76717 80026 143308 1785522 1797658',X'0C0808030808080308040404029E6802B7DC0108ACBA0132DD7B0087795F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 140297 140297 140297 140297 206 188 90 1 1','0 0 1951850 1951850 1951850 1951850 2020506 2020524 2020622 2020711 2020711','0 0 146 146 146 146 85439 89181 160816 2006993 2020711',X'0C0808030808080302040403029E8102171603E800FA82B20132B5AD384ECD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 132041 132041 132041 132041 173 173 20 1 1','0 0 2415706 2415706 2415706 2415706 2428962 2428962 2429115 2429134 2429134','0 0 163 163 163 163 100984 105182 186071 2412732 2429134',X'0C0808030808080308030403029EB1018BF55020D60131A3D23BB156'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 6830 6830 6830 6830 35 35 35 1 1','0 0 2595444 2595444 2595444 2595444 2595711 2595711 2595711 2595739 2595739','0 0 169 169 169 169 108584 113037 199947 2578183 2595739',X'0C0808030808080308030403029EC001878C17A7520131A43A6E513C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 101615 101615 101615 101615 244 33 33 1 1','0 0 2999185 2999185 2999185 2999185 3019255 3019466 3019466 3019498 3019498','0 0 213 213 213 213 131035 136293 237357 2999333 3019498',X'0C080803080808030203040302D7C001B93E03F041A96D013303017C72B6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 26914 26914 26914 26914 87 87 73 1 1','0 0 3868553 3868553 3868553 3868553 3893568 3893568 3893582 3893609 3893609','0 0 387 387 387 387 172456 180121 311050 3869040 3893609',X'0C08080308080803080304040498C86B7EF347CC5A0132B678008A4646'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 97492 97492 97492 97492 410 410 44 1 1','0 0 4948831 4948831 4948831 4948831 5009456 5009456 5009822 5009865 5009865','0 0 751 751 751 751 226745 236274 399260 4980988 5009865',X'0C08080308080803080404030E565F03686C00F89CD001332A115479DC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 1782 1782 1782 1782 52 52 52 1 1','0 0 5190938 5190938 5190938 5190938 5191434 5191434 5191434 5191479 5191479','0 0 800 800 800 800 236362 246237 414618 5161779 5191479',X'0C08080308080803080304040EBD0F0268E064A6DB013242CB00875BAF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 4645 4645 4645 4645 17 17 17 1 1','0 0 6485214 6485214 6485214 6485214 6489339 6489339 6489339 6489349 6489349','0 0 1396 1396 1396 1396 317293 329836 538486 6453712 6489349',X'0C080804080808040803040300ABD9B000A69D33737CBB01328F6B0F6298'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 290196 290196 290196 290196 138 138 26 1 1','0 0 6734628 6734628 6734628 6734628 6744872 6744872 6744984 6745009 6745009','0 0 1641 1641 1641 1641 338986 352099 569319 6708651 6745009',X'0C080804080808030804040400FF5594018819010B3C670133294300B1674C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 630326 24310 1435 1435 1435 1 1 1 1 1','0 7173953 7763625 7786500 7786500 7786500 7787219 7787219 7787219 7787219 7787219','0 1 3518 4119 4119 4119 726018 753845 1215054 7745002 7787219',X'0C080904010808030204040400FF5594070357AB232800F2FA440133294600A90441'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 114188 114188 114188 114188 463 61 61 1 1','7804279 7804279 7809377 7809377 7809377 7809377 7864755 7865157 7865157 7865217 7865217','1 2 3751 4413 4413 4413 740133 768607 1233927 7822883 7865217',X'0C0908030808080302030403018A750213B2245416DF860131CB3A2879CC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 86108 86108 86108 86108 605 605 605 1 1','7804279 7804279 8403815 8403815 8403815 8403815 8463845 8463845 8463845 8464449 8464449','1 2 3805 4467 4467 4467 760796 789718 1255047 8421249 8464449',X'0C0908030808080308030403021FFC0DC36E1AD36901328E2F3D9128'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 60490 60490 60490 60490 44 44 44 1 1','7804279 7804279 9062901 9062901 9062901 9062901 9085056 9085056 9085056 9085089 9085089','1 2 3845 4507 4507 4507 778931 808217 1273550 9040805 9085089',X'0C0908030808080308040403029EB101C30B00E889140132697F092505'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 57304 57304 57304 57304 2 2 2 1 1','7804279 7804279 10328144 10328144 10328144 10328144 10382958 10382958 10382958 10382959 10382959','1 2 4106 4768 4768 4768 823966 853934 1319290 10336860 10382959',X'0C09080308080804080404040E565F00CE8C3100E7F68D0133517900B0B4CE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 174377 174377 174377 174377 81 81 66 1 1','7804279 7804279 11246252 11246252 11246252 11246252 11358749 11358749 11358764 11358829 11358829','1 2 4517 5179 5179 5179 867595 898252 1363807 11311829 11358829',X'0C090804080808030804040300FF55940E584300F2FA44013240670E2E89'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 157757 15066 15066 15066 15066 1 1 1 1 1','7804279 11523070 11657249 11657249 11657249 11657249 11672314 11672314 11672314 11672314 11672314','1 3 5503 6167 6167 6167 1025351 1059076 1524822 11625280 11672314',X'0C090904080808040203040300FF5594025D19032328337763013351F2277A3E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4748 4629 4629 4629 4629 17 1 1 1','0 0 634880 634880 634880 634880 634880 639175 639191 639191 639191','0 0 779 907 907 907 907 415429 633684 633685 639191',X'0C0808030808080804030303018C4A013157983CE7FE05E54B6BB7FB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4608 4608 4608 4608 4608 33 1 1 1','0 0 752580 752580 752580 752580 752580 755506 755538 755538 755538','0 0 936 1089 1089 1089 1089 491324 749126 749127 755538',X'0C0808030808080804030303018D4F0131A682512ECF029E6A70A9E9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4776 4776 4776 4776 4776 27 1 1 1','0 0 762070 762070 762070 762070 762070 763357 763383 763383 763383','0 0 940 1097 1097 1097 1097 495628 756890 756891 763383',X'0C0808030808080804040303018D560132DB8800F3416D029EA654D9AC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5910 5910 5910 5910 5910 37 2 2 1','0 0 771353 771353 771353 771353 771353 775562 775597 775597 775598','0 0 946 1103 1103 1103 1103 501111 769013 769014 775598',X'0C0808030808080804030303018D610131CADE4C6E2D01D5860141A9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 1834 1834 1834 1834 1834 6 1 1 1','0 0 1296866 1296866 1296866 1296866 1296866 1297867 1297869 1297869 1297869','0 0 2621 2842 2842 2842 2842 857867 1287063 1287064 1297869',X'0C080803080808080403030301A6E30132419A1E1B7F0567EE2880C0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5007 3959 3959 3959 3959 25 1 1 1','0 0 2152400 2152400 2152400 2152400 2152400 2155551 2155575 2155575 2155575','0 0 5683 6304 6304 6304 6304 1442790 2140930 2140937 2155575',X'0C080803080808080404030301C3F901317CC701044CC7029E6834F7E2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4768 4609 4609 4609 4609 26 1 1 1','0 0 2200466 2200466 2200466 2200466 2200466 2204364 2204389 2204389 2204389','0 0 5714 6370 6370 6370 6370 1470393 2189496 2189503 2204389',X'0C080803080808080403030301C4220131586B3EB735018A7567CE9E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5177 4669 4669 4669 4669 22 1 1 1','0 0 2234078 2234078 2234078 2234078 2234078 2238366 2238387 2238387 2238387','0 0 5743 6422 6422 6422 6422 1490145 2223355 2223362 2238387',X'0C080803080808080403030301C4490131573F4104F802D9CA67FD1E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 7981 5546 5546 5546 5546 32 1 1 1','0 0 2239923 2239923 2239923 2239923 2239923 2243388 2243419 2243419 2243419','0 0 5746 6428 6428 6428 6428 1492784 2228358 2228365 2243419',X'0C080803080808080404030301C44E0131A4FE00FDCC04029E8175076B'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 351 336 336 336 336 1 1 1 1','0 0 2595725 2595725 2595725 2595725 2595725 2595739 2595739 2595739 2595739','0 0 6747 7717 7717 7717 7717 1732397 2578697 2578708 2595739',X'0C080803080808080404030301CCC901332A7700F17E5D0E5D6F523B01'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 6022 4942 4942 4942 4942 38 1 1 1','0 0 2648510 2648510 2648510 2648510 2648510 2652126 2652163 2652163 2652163','0 0 6934 7959 7959 7959 7959 1770411 2634884 2634898 2652163',X'0C080803080808080404030301CE8C01317DE800FE4E8B029E81458317'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4752 1965 1965 1965 1965 1 1 1 1','0 0 3161780 3161780 3161780 3161780 3161780 3163744 3163744 3163744 3163744','0 0 9707 11219 11219 11219 11219 2143797 3143873 3143896 3163744',X'0C08080308080808040303030213B20130BC9216F939029E815B86EE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5497 1880 1880 1880 1880 1 1 1 1','0 0 3167643 3167643 3167643 3167643 3167643 3169522 3169522 3169522 3169522','0 0 9709 11226 11226 11226 11226 2148088 3149632 3149655 3169522',X'0C08080308080808040303030213B50130BBC616FC6501C7A62A1BB2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 2185 2126 2126 2126 2126 4 1 1 1','0 0 3891670 3891670 3891670 3891670 3891670 3893609 3893609 3893609 3893609','0 0 13596 15952 15953 15953 15953 2677069 3869700 3869732 3893609',X'0C080803080808080403030302BD5F01317CC81782F704C9D95EFF0C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5511 5355 5355 5355 5355 21 1 1 1','0 0 3931850 3931850 3931850 3931850 3931850 3936206 3936226 3936226 3936226','0 0 13793 16188 16189 16189 16189 2705655 3912091 3912125 3936226',X'0C080803080808080403030302C14C01317C514010FA01B64235E688'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5468 5115 5115 5115 5115 27 1 1 1','0 0 3939091 3939091 3939091 3939091 3939091 3943255 3943281 3943281 3943281','0 0 13803 16200 16201 16201 16201 2709082 3919099 3919133 3943281',X'0C080803080808080403030302C16401317CC348B67001C3EB6824BB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5275 4792 4792 4792 4792 31 1 1 1','0 0 4590217 4590217 4590217 4590217 4590217 4591639 4591669 4591669 4591669','0 0 17456 20455 20456 20456 20456 3175906 4564022 4564064 4591669',X'0C0808030808080804040403049EE50132915200FA2F9300EA0DC50554E0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 339 339 339 339 339 2 1 1 1','0 0 5191258 5191258 5191258 5191258 5191258 5191478 5191479 5191479 5191479','0 0 20754 24230 24231 24231 24231 3601696 5160652 5160701 5191479',X'0C08080308080808040303030CEE930132671A1B8AFF01B6426386D0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 13 13 13 13 13 1 1 1 1','0 0 6489339 6489339 6489339 6489339 6489339 6489349 6489349 6489349 6489349','0 0 29449 33987 33989 33989 33989 4540005 6453309 6453378 6489349',X'0C08080408080808040303030091B3AB01321B5A4F26F2018A750B6686'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 630326 19 19 18 18 18 1 1 1 1','0 7173953 7787203 7787203 7787203 7787203 7787203 7787219 7787219 7787219 7787219','0 1 73522 83967 91688 91688 91688 5643606 7744920 7744997 7787219',X'0C080904080808080404030300FF69210132DB2900FB0715029EB573EB9F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','3876548 3718791 4598 4512 4512 4512 4512 38 1 1 1','7804279 7804279 8237877 8237877 8237877 8237877 8237877 8238986 8239023 8239023 8239023','1 2 76726 87349 95641 95641 95641 5923145 8195880 8195957 8239023',X'0C0908030808080804040404018D3F01332A780111068001FB6F840083BEF9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','3876548 3718791 397 397 397 397 397 2 1 1 1','7804279 7804279 9084892 9084892 9084892 9084892 9084892 9085089 9085089 9085089 9085089','1 2 79826 90851 99143 99143 99143 6505397 9040540 9040617 9085089',X'0C090803080808080403030301CBAF0133028A4E35BE715A2A49098C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','3876548 3718791 141 141 141 141 141 2 1 1 1','7804279 7804279 10382921 10382921 10382921 10382921 10382921 10382958 10382959 10382959 10382959','1 2 87296 99145 107437 107437 107437 7432077 10336699 10336776 10382959',X'0C09080308080808040403030DB5C101332BF7010E37310EB97420BFF6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','3876548 157757 83 16 16 16 16 1 1 1 1','7804279 11523070 11587750 11587817 11587817 11587817 11587817 11587832 11587832 11587832 11587832','1 3 104655 118035 126343 126343 126343 8311754 11540721 11540798 11587832',X'0C090903020808080404030402A9D1232801332CC300EB7D35029E83008581B1'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 24157 24157 24157 24157 24157 133 1 1 1','0 0 1236590 1236590 1236590 1236590 1236590 1241150 1241282 1241282 1241282','0 0 3120 3120 3120 3120 4771 741878 1223262 1228239 1241282',X'0C08080308080804040408031A080400FF559401321BC20099C49F3BE84C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 1209 1209 1209 1209 1209 2 1 1 1','0 0 1296873 1296873 1296873 1296873 1296873 1297868 1297869 1297869 1297869','0 0 3203 3203 3203 3203 4902 763298 1279554 1284645 1297869',X'0C08080308080803040308031A215F04C9D901317D1501B0A355A290'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 12129 12129 12129 12129 9261 38 1 1 1','0 0 1790076 1790076 1790076 1790076 1790076 1791737 1791774 1791774 1791774','0 0 4938 4938 4938 4938 7561 1075153 1767990 1775629 1791774',X'0C08080308080803040408031CE87E029E6B01328F6100B473FD5BE552'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 273 273 273 273 273 1 1 1 1','0 0 2595625 2595625 2595625 2595625 2595625 2595739 2595739 2595739 2595739','0 0 7863 7863 7863 7863 12132 1580849 2562484 2575172 2595739',X'0C08080308080803040308032F020502DA0E013241A16B73DE01E021'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 7735 7735 7735 7735 7735 503 1 1 1','0 0 2924165 2924165 2924165 2924165 2924165 2931394 2931896 2931896 2931896','0 0 9123 9123 9123 9123 14045 1794002 2895440 2909856 2931896',X'0C080803080808040404080433776300FF55940133294301C56631008BCB5A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 360 360 360 360 229 1 1 1 1','0 0 3893374 3893374 3893374 3893374 3893505 3893609 3893609 3893609 3893609','0 0 13912 13912 13912 13912 21124 2420346 3846830 3866425 3893609',X'0C08080308080803040308034717710E070B01317F7102C73A396CE1'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 683 683 683 683 671 2 1 1 1','0 0 5191447 5191447 5191447 5191447 5191459 5191479 5191479 5191479 5191479','0 0 20361 20361 20361 20361 30776 3226670 5127525 5158962 5191479',X'0C08080308080803040308037370D10F00290132B59A018F7A694C9B'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 213354 213354 213354 213354 213354 5934 1 1 1','0 0 6102233 6102233 6102233 6102233 6102233 6154276 6155650 6155650 6155650','0 0 26812 26812 26812 26812 39489 3770219 6079715 6119855 6155650',X'0C080804080808040403080300F2FA4400FF55940132DF1A01C0C115D4D4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 3675 3675 3675 3675 3675 14 1 1 1','0 0 6486701 6486701 6486701 6486701 6486701 6489347 6489349 6489349 6489349','0 0 28380 28380 28380 28380 41383 3868787 6409451 6452691 6489349',X'0C080804080808030403020300F6ABAC6C967D0132B672026C8D03E8155844'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 24063 24063 24063 24063 24063 1799 1 1 1','0 0 7080914 7080914 7080914 7080914 7080914 7103178 7104976 7104976 7104976','0 0 35724 35725 35725 35725 49845 4189282 7019641 7067879 7104976',X'0C0808040808080404040804010B0A5C00FF55940133294301D2C35700A877B5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 20284 20284 20284 20284 20284 1518 1 1 1','0 0 7107240 7107240 7107240 7107240 7107240 7124584 7126101 7126101 7126101','0 0 35764 35765 35765 35765 49886 4191089 7040717 7089004 7126101',X'0C0808040808080404040803010B3C6700FF55940133294501F0A829511573'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 630326 13288 11855 11855 11855 11855 5449 1 1 1','0 7173953 7671119 7671119 7671119 7671119 7671119 7676514 7676526 7676526 7676526','0 1 64320 65543 65543 65543 92453 4431581 7580039 7634401 7676526',X'0C080904080808040403080400F2FA4400FF5594013329430186CB00A866E4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 630326 61 61 61 61 61 14 1 1 1','0 7173953 7787172 7787172 7787172 7787172 7787172 7787217 7787219 7787219 7787219','0 1 73272 75274 75274 75274 103642 4468650 7689369 7745002 7787219',X'0C0809040808080304030803010ABA910DD2420133068F05DE6223042F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 8657 8657 8657 8657 8657 18 1 1 1','7804279 7804279 8360485 8360485 8360485 8360485 8360485 8360977 8360994 8360994 8360994','1 2 75785 77865 77865 77865 106290 4756698 8258979 8317590 8360994',X'0C09080308080803040408031AD369021FFC0133517F01B017F259F6C3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 33421 33421 33421 33421 33421 2221 1 1 1','7804279 7804279 8873934 8873934 8873934 8873934 8873934 8874868 8877088 8877088 8877088','1 2 76834 78914 78914 78914 107340 5041847 8770182 8832668 8877088',X'0C090803080808040404020333776300FF5594013351790241FEE4232825FB3D'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 2182 2182 2182 2182 2182 20 1 1 1','7804279 7804279 9083187 9083187 9083187 9083187 9083187 9085087 9085089 9085089 9085089','1 2 77227 79307 79307 79307 107733 5141706 8974619 9040316 9085089',X'0C09080308080803040308043AC92C021FFC0132B668018BAB00964778'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 6008 6008 6008 6008 6008 26 1 1 1','7804279 7804279 9124662 9124662 9124662 9124662 9124662 9128286 9128311 9128311 9128311','1 2 77300 79380 79380 79380 107806 5160088 9016921 9083451 9128311',X'0C09080308080804040408033C1C5C00F024880132DB2100B88E8A420C1B'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 6023 6023 6023 6023 6023 91 1 1 1','7804279 7804279 9393480 9393480 9393480 9393480 9393480 9396519 9396609 9396609 9396609','1 2 77893 79973 79973 79973 108402 5311949 9282988 9351281 9396609',X'0C09080308080803040408044CDD9A7E1C230132DE4200D105C800A087F7'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 79 79 79 79 79 1 1 1 1','7804279 7804279 10382946 10382946 10382946 10382946 10382946 10382959 10382959 10382959 10382959','1 2 80421 82501 82501 82501 110947 5821380 10258569 10336296 10382959',X'0C090804080808030403080300E9A10A0CC3160133505F0D25365733C6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 8251 8251 8251 8251 8251 37 1 1 1','7804279 7804279 11067468 11067468 11067468 11067468 11067468 11068084 11068120 11068120 11068120','1 2 83449 85529 85529 85529 113989 6177561 10936213 11021086 11068120',X'0C090804080808040404080400FFA4A7008A66AD01332AD10170A8B10084054A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 44772 44772 44772 44772 44772 3018 1 1 1','7804279 7804279 11268036 11268036 11268036 11268036 11268036 11282829 11285846 11285846 11285846','1 2 85052 87132 87132 87132 115597 6281979 11151347 11238812 11285846',X'0C0908040808080404040804010B0A5C00FF5594013351720249087400B0523C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 53775 53775 53775 53775 53775 4069 1 1 1','7804279 7804279 11330929 11330929 11330929 11330929 11330929 11359035 11363103 11363103 11363103','1 2 85255 87335 87335 87335 115800 6292285 11227544 11316069 11363103',X'0C0908040808080404040804010BFA8100FF5594013351280252F8A000B01818'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 39430 39430 39430 39430 39430 3018 1 1 1','7804279 7804279 11458789 11458789 11458789 11458789 11458789 11468188 11471205 11471205 11471205','1 2 86422 88502 88502 88502 116970 6333877 11333316 11424171 11471205',X'0C09080408080804040408040113B99600FF559401335174024530C4008AC82C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 157757 5317 5317 5317 5317 5317 12 1 1 1','7804279 11523070 11652844 11652844 11652844 11652844 11652844 11658149 11658160 11658160 11658160','1 3 97969 100051 100051 100051 128567 6429914 11517744 11611126 11658160',X'0C0909040808080404040804010BFA8100FF559401332B2E01521E0B008447F4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 24157 29 29 29 29 29 1 1 1','0 0 1236590 1251799 1251799 1251799 1251799 1251799 1251827 1251827 1251827','0 0 3120 62451 63798 63798 63798 63798 1238772 1238782 1251827',X'0C08080303080808080404031A0804029BB30131CD3700FF55942B1368'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 1209 129 129 129 129 129 1 1 1','0 0 1296873 1297744 1297744 1297744 1297744 1297744 1297869 1297869 1297869','0 0 3203 65280 66657 66657 66657 66657 1284635 1284645 1297869',X'0C08080303080808080403041A215F01B0A30131066F04C9D90087162A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 12129 604 604 604 604 604 1 1 1','0 0 1790076 1790076 1790076 1790076 1790076 1790076 1790679 1790679 1790679','0 0 4938 95334 97612 97612 97612 97612 1774566 1774578 1790679',X'0C08080303080808080403031CE87E01870001317C4D0CED622FE2E8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 273 5 5 5 5 5 1 1 1','0 0 2595625 2595738 2595738 2595738 2595738 2595738 2595739 2595739 2595739','0 0 7863 145612 149427 149427 149427 149427 2575145 2575172 2595739',X'0C08080303080808080403042F020502C73A0133049702DA0E00A711F8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 7735 29 29 29 29 29 1 1 1','0 0 2924165 2929754 2929754 2929754 2929754 2929754 2929782 2929782 2929782','0 0 9123 167852 172269 172269 172269 172269 2907715 2907742 2929782',X'0C080803030808080804040333776375928D0133294300FF55945A824F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 360 6 6 6 6 6 1 1 1','0 0 3893374 3893607 3893607 3893607 3893607 3893607 3893609 3893609 3893609','0 0 13912 240908 247109 247109 247109 247109 3866384 3866425 3893609',X'0C080803030808080804030347177104AF8701317D220E070B687905'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 683 32 32 32 32 32 2 2 1','0 0 5191447 5191465 5191465 5191465 5191465 5191465 5191479 5191479 5191479','0 0 20361 336764 345696 345696 345696 345696 5158907 5158962 5191479',X'0C08080303080808080403037370D101884501328F690F002900A69C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 213354 113 113 113 113 113 1 1 1','0 0 6102233 6155183 6155183 6155183 6155183 6155183 6155295 6155295 6155295','0 0 26812 421693 433202 433202 433202 433202 6119212 6119281 6155295',X'0C080804030808080804040300F2FA44019B6D0132406700FF5594714AE8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 3675 241 241 241 241 241 1 1 1','0 0 6486701 6489287 6489287 6489287 6489287 6489287 6489349 6489349 6489349','0 0 28380 450494 462953 462953 462953 462953 6452616 6452691 6489349',X'0C080804040808080804030300F6ABAC009F84B60132DBDD6C967D155A2A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 24063 38 38 38 38 38 1 1 1','0 0 7080914 7102383 7102383 7102383 7102383 7102383 7102420 7102420 7102420','0 0 35724 528136 541855 541858 541858 541858 7065247 7065323 7102420',X'0C0808040408080808040403010B0A5C00CCD3EE0133294500FF559459DDCD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 20284 38 38 38 38 38 1 1 1','0 0 7107240 7126609 7126609 7126609 7126609 7126609 7126646 7126646 7126646','0 0 35764 531673 545484 545487 545487 545487 7089473 7089549 7126646',X'0C0808040408080808040403010B3C670114CE730133294300FF55942225CC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 630326 13288 5 1 1 1 1 1 1 1','0 7173953 7671119 7675167 7675171 7675171 7675171 7675171 7675171 7675171 7675171','0 1 64320 967583 993386 999414 999414 999414 7632969 7633046 7675171',X'0C080904030308080804040400F2FA4401D16F0183350132DEFE00FF5594009FA501'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 630326 61 1 1 1 1 1 1 1 1','0 7173953 7787172 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219','0 1 73272 1068631 1096442 1107608 1107608 1107608 7744925 7745002 7787219',X'0C0809040408080808040304010ABA9100AA4C1F013351DB0DD242008BFFEF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 8657 605 605 605 605 605 1 1 1','7804279 7804279 8360485 8364643 8364643 8364643 8364643 8364643 8365247 8365247 8365247','1 2 75785 1096159 1124446 1135923 1135923 1135923 8321766 8321843 8365247',X'0C09080303080808080403031AD3690DC36E01328E2F021FFC3D9128'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 33421 57 26 26 26 26 1 1 1','7804279 7804279 8873934 8891008 8891039 8891039 8891039 8891039 8891064 8891064 8891064','1 2 76834 1110063 1138607 1150084 1150084 1150084 8846567 8846644 8891064',X'0C09080303020808080404043377630CE166232801332A1800FF559400836DFB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 2182 94 94 94 94 94 1 1 1','7804279 7804279 9083187 9085006 9085006 9085006 9085006 9085006 9085089 9085089 9085089','1 2 77227 1115805 1144438 1155915 1155915 1155915 9040239 9040316 9085089',X'0C09080303080808080403033AC92C04AF670132B5FC021FFC38DBD0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 6008 277 277 277 277 277 1 1 1','7804279 7804279 9124662 9124662 9124662 9124662 9124662 9124662 9124938 9124938 9124938','1 2 77300 1116652 1145304 1156781 1156781 1156781 9080000 9080077 9124938',X'0C09080303080808080404033C1C5C01B49901328DDA00F024883D6052'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 6023 50 50 50 50 50 1 1 1','7804279 7804279 9393480 9395815 9395815 9395815 9395815 9395815 9395864 9395864 9395864','1 2 77893 1123924 1152663 1164140 1164140 1164140 9350459 9350536 9395864',X'0C09080303080808080403034CDD9A01C30D013290877E1C2303CC11'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 79 6 6 6 6 6 1 1 1','7804279 7804279 10382946 10382956 10382956 10382956 10382956 10382956 10382959 10382959 10382959','1 2 80421 1154920 1184197 1195674 1195674 1195674 10336219 10336296 10382959',X'0C090804030808080804030400E9A10A02A47201332C6C0CC31600ABCD60'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 8251 280 280 280 280 280 1 1 1','7804279 7804279 11067468 11072690 11072690 11072690 11072690 11072690 11072969 11072969 11072969','1 2 83449 1186373 1216159 1227636 1227636 1227636 11025858 11025935 11072969',X'0C090804040808080804040300FFA4A70089DBDD0132B5FF008A66AD6AE2B8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 44772 58 58 58 58 58 1 1 1','7804279 7804279 11268036 11269261 11269261 11269261 11269261 11269261 11269318 11269318 11269318','1 2 85052 1199706 1229712 1241189 1241189 1241189 11222207 11222284 11269318',X'0C0908040308080808040404010B0A5C018ACD0133294300FF559400B0E291'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 53775 37 19 19 19 19 1 1 1','7804279 7804279 11330929 11355027 11355045 11355045 11355045 11355045 11355063 11355063 11355063','1 2 85255 1206165 1236304 1247781 1247781 1247781 11307952 11308029 11355063',X'0C0908040302080808040403010BFA81026C24232801332B2E00FF55941F8BB5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 39430 39 39 39 39 39 1 1 1','7804279 7804279 11458789 11476757 11476757 11476757 11476757 11476757 11476795 11476795 11476795','1 2 86422 1219089 1249476 1260953 1260953 1260953 11429684 11429761 11476795',X'0C09080403080808080404030113B99602F6AF01332B2E00FF55941F8A54'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 157757 5317 1 1 1 1 1 1 1 1','7804279 11523070 11652844 11658160 11658160 11658160 11658160 11658160 11658160 11658160 11658160','1 3 97969 1358780 1391643 1403122 1403122 1403122 11611049 11611126 11658160',X'0C0909040402080808040403010BFA8102594CCB2328013351E800FF55945B0F5D'); + ANALYZE sqlite_master; +} {} + +# Ensure that the query planner implements the GROUP BY using a separate sort +# +do_execsql_test whereJ-1.4 { + EXPLAIN QUERY PLAN + SELECT aid, sid, MAX(edate) edate + FROM tx1 + WHERE cid = 115790 + AND sid = 9100 + AND edate <= 20140430 AND edate >= 20120429 + GROUP BY aid; +} {/B-TREE/} + +############################################################################ +# Ensure that the sorting cost does not swamp the loop costs and cause +# distinctions between individual loop costs to get lost, and hence for +# sub-optimal loops to be chosen. +# +do_execsql_test whereJ-2.1 { + CREATE TABLE tab( + id INTEGER PRIMARY KEY, + minChild INTEGER REFERENCES t1, + maxChild INTEGER REFERENCES t1, + x INTEGER + ); + EXPLAIN QUERY PLAN + SELECT t4.x + FROM tab AS t0, tab AS t1, tab AS t2, tab AS t3, tab AS t4 + WHERE t0.id=0 + AND t1.id BETWEEN t0.minChild AND t0.maxChild + AND t2.id BETWEEN t1.minChild AND t1.maxChild + AND t3.id BETWEEN t2.minChild AND t2.maxChild + AND t4.id BETWEEN t3.minChild AND t3.maxChild + ORDER BY t4.x; +} {~/SCAN/} +do_execsql_test whereJ-2.2 { + EXPLAIN QUERY PLAN + SELECT t4.x + FROM tab AS t0a, tab AS t0b, + tab AS t1a, tab AS t1b, + tab AS t2a, tab AS t2b, + tab AS t3a, tab AS t3b, + tab AS t4 + WHERE 1 + AND t0a.id=1 + AND t1a.id BETWEEN t0a.minChild AND t0a.maxChild + AND t2a.id BETWEEN t1a.minChild AND t1a.maxChild + AND t3a.id BETWEEN t2a.minChild AND t2a.maxChild + AND t0b.id=2 + AND t1b.id BETWEEN t0b.minChild AND t0b.maxChild + AND t2b.id BETWEEN t1b.minChild AND t1b.maxChild + AND t3b.id BETWEEN t2b.minChild AND t2b.maxChild + AND t4.id BETWEEN t3a.minChild AND t3b.maxChild + ORDER BY t4.x; +} {~/SCAN/} + + +finish_test diff --git a/test/wild001.test b/test/wild001.test new file mode 100644 index 0000000..7fe1404 --- /dev/null +++ b/test/wild001.test @@ -0,0 +1,311 @@ +# 2013-07-01 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This is a test case from content taken "from the wild". In this +# particular instance, the query was provided with permission by +# Elan Feingold on 2013-06-27. His message on the SQLite mailing list +# on that date reads: +# +#------------------------------------------------------------------------------ +# > Can you send (1) the schema (2) the query that is giving problems, and (3) +# > the content of the sqlite_stat1 table after you have run ANALYZE? If you +# > can combine all of the above into a script, that would be great! +# > +# > If you send (1..3) above and you give us written permission to include the +# > query in our test suite, that would be off-the-chain terrific. +# +# Please find items 1..3 in this file: http://www.plexapp.com/elan/sqlite_bug.txt +# +# You have our permission to include the query in your test suite. +# +# Thanks for an amazing product. +#----------------------------------------------------------------------------- +# +# This test case merely creates the schema and populates SQLITE_STAT1 and +# SQLITE_STAT3 then runs an EXPLAIN QUERY PLAN to ensure that the right plan +# is discovered. This test case may need to be adjusted for future revisions +# of the query planner manage to select a better query plan. The query plan +# shown here is known to be very fast with the original data. +# +# This test should work the same with and without SQLITE_ENABLE_STAT3 +# +############################################################################### + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !stat3 { + finish_test + return +} + +do_execsql_test wild001.01 { + CREATE TABLE "items" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "secid" integer, "parent_id" integer, "metadata_type" integer, "guid" varchar(255), "media_item_count" integer, "title" varchar(255), "title_sort" varchar(255) COLLATE NOCASE, "original_title" varchar(255), "studio" varchar(255), "rating" float, "rating_count" integer, "tagline" varchar(255), "summary" text, "trivia" text, "quotes" text, "content_rating" varchar(255), "content_rating_age" integer, "index" integer, "absolute_index" integer, "duration" integer, "user_thumb_url" varchar(255), "user_art_url" varchar(255), "user_banner_url" varchar(255), "user_music_url" varchar(255), "user_fields" varchar(255), "tags_genre" varchar(255), "tags_collection" varchar(255), "tags_director" varchar(255), "tags_writer" varchar(255), "tags_star" varchar(255), "originally_available_at" datetime, "available_at" datetime, "expires_at" datetime, "refreshed_at" datetime, "year" integer, "added_at" datetime, "created_at" datetime, "updated_at" datetime, "deleted_at" datetime, "tags_country" varchar(255), "extra_data" varchar(255), "hash" varchar(255)); + CREATE INDEX "i_secid" ON "items" ("secid" ); + CREATE INDEX "i_parent_id" ON "items" ("parent_id" ); + CREATE INDEX "i_created_at" ON "items" ("created_at" ); + CREATE INDEX "i_index" ON "items" ("index" ); + CREATE INDEX "i_title" ON "items" ("title" ); + CREATE INDEX "i_title_sort" ON "items" ("title_sort" ); + CREATE INDEX "i_guid" ON "items" ("guid" ); + CREATE INDEX "i_metadata_type" ON "items" ("metadata_type" ); + CREATE INDEX "i_deleted_at" ON "items" ("deleted_at" ); + CREATE INDEX "i_secid_ex1" ON "items" ("secid", "metadata_type", "added_at" ); + CREATE INDEX "i_hash" ON "items" ("hash" ); + CREATE TABLE "settings" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "account_id" integer, "guid" varchar(255), "rating" float, "view_offset" integer, "view_count" integer, "last_viewed_at" datetime, "created_at" datetime, "updated_at" datetime); + CREATE INDEX "s_account_id" ON "settings" ("account_id" ); + CREATE INDEX "s_guid" ON "settings" ("guid" ); + ANALYZE; + INSERT INTO sqlite_stat1 VALUES('settings','s_guid','4740 1'); + INSERT INTO sqlite_stat1 VALUES('settings','s_account_id','4740 4740'); + INSERT INTO sqlite_stat1 VALUES('items','i_hash','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_secid_ex1','27316 6829 4553 3'); + INSERT INTO sqlite_stat1 VALUES('items','i_deleted_at','27316 27316'); + INSERT INTO sqlite_stat1 VALUES('items','i_metadata_type','27316 6829'); + INSERT INTO sqlite_stat1 VALUES('items','i_guid','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_title_sort','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_title','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_index','27316 144'); + INSERT INTO sqlite_stat1 VALUES('items','i_created_at','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_parent_id','27316 15'); + INSERT INTO sqlite_stat1 VALUES('items','i_secid','27316 6829'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,150,150,'com.plexapp.agents.thetvdb://153021/2/9?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,198,198,'com.plexapp.agents.thetvdb://194031/1/10?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,526,526,'com.plexapp.agents.thetvdb://71256/12/92?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,923,923,'com.plexapp.agents.thetvdb://71256/15/16?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1008,1008,'com.plexapp.agents.thetvdb://71256/15/93?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1053,1053,'com.plexapp.agents.thetvdb://71256/16/21?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1068,1068,'com.plexapp.agents.thetvdb://71256/16/35?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1235,1235,'com.plexapp.agents.thetvdb://71256/17/44?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1255,1255,'com.plexapp.agents.thetvdb://71256/17/62?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1573,1573,'com.plexapp.agents.thetvdb://71663/20/9?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1580,1580,'com.plexapp.agents.thetvdb://71663/21/16?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2000,2000,'com.plexapp.agents.thetvdb://73141/9/8?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2107,2107,'com.plexapp.agents.thetvdb://73244/6/17?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2256,2256,'com.plexapp.agents.thetvdb://74845/4/7?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2408,2408,'com.plexapp.agents.thetvdb://75978/2/21?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2634,2634,'com.plexapp.agents.thetvdb://79126/1/1?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2962,2962,'com.plexapp.agents.thetvdb://79274/3/94?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3160,3160,'com.plexapp.agents.thetvdb://79274/5/129?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3161,3161,'com.plexapp.agents.thetvdb://79274/5/12?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3688,3688,'com.plexapp.agents.thetvdb://79274/8/62?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3714,3714,'com.plexapp.agents.thetvdb://79274/8/86?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,4002,4002,'com.plexapp.agents.thetvdb://79590/13/17?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,4215,4215,'com.plexapp.agents.thetvdb://80727/3/6?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,4381,4381,'com.plexapp.agents.thetvdb://83462/3/24?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_account_id',4740,0,0,1); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,1879,1879,'1113f632ccd52ec8b8d7ca3d6d56da4701e48018'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,2721,2721,'1936154b97bb5567163edaebc2806830ae419ccf'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,3035,3035,'1c122331d4b7bfa0dc2c003ab5fb4f7152b9987a'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,3393,3393,'1f81bdbc9acc3321dc592b1a109ca075731b549a'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,6071,6070,'393cf7713efb4519c7a3d1d5403f0d945d15a16a'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,7462,7461,'4677dd37011f8bd9ae7fbbdd3af6dcd8a5b4ab2d'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,8435,8434,'4ffa339485334e81a5e12e03a63b6508d76401cf'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,8716,8714,'52a093852e6599dd5004857b7ff5b5b82c7cdb25'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,9107,9104,'561183e39f866d97ec728e9ff16ac4ad01466111'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,10942,10939,'66e99b72e29610f49499ae09ee04a376210d1f08'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,12143,12139,'71f0602427e173dc2c551535f73fdb6885fe4302'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,14962,14958,'8ca8e4dfba696019830c19ab8a32c7ece9d8534b'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,15179,15174,'8ebf1a5cf33f8ada1fc5853ac06ac4d7e074f825'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,15375,15370,'908bc211bebdf21c79d2d2b54ebaa442ac1f5cae'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,18215,18210,'ab29e4e18ec5a14fef95aa713d69e31c045a22c1'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,18615,18610,'ae84c008cc0c338bf4f28d798a88575746452f6d'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,18649,18644,'aec7c901353e115aa5307e94018ba7507bec3a45'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,19517,19512,'b75025fbf2e9c504e3c1197ff1b69250402a31f8'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,21251,21245,'c7d32f0e3a8f3a0a3dbd00833833d2ccee62f0fd'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,23616,23610,'dd5ff61479a9bd4100de802515d9dcf72d46f07a'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,24287,24280,'e3db00034301b7555419d4ef6f64769298d5845e'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,24949,24942,'ea336abd197ecd7013854a25a4f4eb9dea7927c6'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,25574,25567,'f018ea5182ec3f32768ca1c3cefbf3ad160ec20b'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,26139,26132,'f53709a8d81c12cb0f4f8d58004a25dd063de67c'); + INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',25167,0,0,2); + INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',736,25167,1,3); + INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',15,25903,2,4); + INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',1398,25918,3,5); + INSERT INTO sqlite_stat3 VALUES('items','i_deleted_at',27316,0,0,NULL); + INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',2149,0,0,1); + INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',411,2149,1,2); + INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',1440,2560,2,3); + INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',23316,4000,3,4); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,215,215,'com.plexapp.agents.imdb://tt0065702?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,711,711,'com.plexapp.agents.imdb://tt0198781?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,987,986,'com.plexapp.agents.imdb://tt0454876?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1004,1002,'com.plexapp.agents.imdb://tt0464154?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1056,1053,'com.plexapp.agents.imdb://tt0499549?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1120,1116,'com.plexapp.agents.imdb://tt0903624?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1250,1245,'com.plexapp.agents.imdb://tt1268799?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1270,1264,'com.plexapp.agents.imdb://tt1320261?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1376,1369,'com.plexapp.agents.imdb://tt1772341?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,3035,3027,'com.plexapp.agents.thetvdb://153021/3/14?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,6071,6063,'com.plexapp.agents.thetvdb://71173/1/18?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,6342,6334,'com.plexapp.agents.thetvdb://71256/13/4?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,9107,9099,'com.plexapp.agents.thetvdb://72389/2/19?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,11740,11732,'com.plexapp.agents.thetvdb://73893/2/13?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,12143,12135,'com.plexapp.agents.thetvdb://73976/4/23?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,15179,15171,'com.plexapp.agents.thetvdb://75897/16/12?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,17408,17400,'com.plexapp.agents.thetvdb://76808/2/16?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,17984,17976,'com.plexapp.agents.thetvdb://77068/1/16?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,18215,18207,'com.plexapp.agents.thetvdb://77259/1/1?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,21251,21243,'com.plexapp.agents.thetvdb://78957/8/2?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,24287,24279,'com.plexapp.agents.thetvdb://80337/5/8?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,25513,25505,'com.plexapp.agents.thetvdb://82226/6?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,25548,25540,'com.plexapp.agents.thetvdb://82339/2/10?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,26770,26762,'com.plexapp.agents.thetvdb://86901/1/3?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1524,0,0,''); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',2,3034,1391,'Attack of the Giant Squid'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',51,4742,2895,'Brad Sherwood'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',11,4912,2996,'Brian Williams'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',39,5847,3857,'Chip Esten'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,6071,4015,'Chuck Versus the DeLorean'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',12,7625,5436,'Denny Siegel'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',30,8924,6618,'Episode 1'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',29,9015,6629,'Episode 2'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',32,9082,6643,'Episode 3'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',28,9135,6654,'Episode 4'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',26,9183,6665,'Episode 5'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',27,9229,6677,'Episode 6'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',22,9266,6688,'Episode 7'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',20,9298,6699,'Episode 8'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',55,11750,8817,'Greg Proops'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,12143,9120,'Hardware Jungle'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',33,14712,11435,'Kathy Greenwood'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',3,15179,11840,'Last Call'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,18215,14601,'Nature or Nurture?'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',12,18241,14623,'Neil DeGrasse Tyson'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',68,19918,16144,'Pilot'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',7,21251,17298,'Reza Aslan'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,24287,20035,'Technoviking'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1524,0,0,''); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,3035,1429,'Anderson Can''t Dance'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',51,4782,2991,'Brad Sherwood'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',11,4936,3079,'Brian Williams'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',39,5694,3783,'Chip Esten'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,6071,4100,'Clive Warren'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',12,7144,5078,'Denny Siegel'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',30,8249,6097,'Episode 1'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',29,8340,6108,'Episode 2'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',32,8407,6122,'Episode 3'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',28,8460,6133,'Episode 4'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',26,8508,6144,'Episode 5'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',27,8554,6156,'Episode 6'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',22,8591,6167,'Episode 7'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',20,8623,6178,'Episode 8'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,9107,6537,'Fat Albert and the Cosby Kids'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',55,10539,7843,'Greg Proops'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,12143,9276,'Iron Age Remains'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',33,13118,10143,'Kathy Greenwood'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,15179,11972,'Mink'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',68,17411,14035,'Pilot'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',2,18214,14727,'Reflections'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',4,21250,17481,'The Apartment'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,24287,20283,'The Simpsons Already Did It'); + INSERT INTO sqlite_stat3 VALUES('items','i_index',4315,95,2,1); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1553,4410,3,2); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1485,5963,4,3); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1414,7448,5,4); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1367,8862,6,5); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1328,10229,7,6); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1161,11557,8,7); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1108,12718,9,8); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1033,13826,10,9); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1014,14859,11,10); + INSERT INTO sqlite_stat3 VALUES('items','i_index',929,15873,12,11); + INSERT INTO sqlite_stat3 VALUES('items','i_index',906,16802,13,12); + INSERT INTO sqlite_stat3 VALUES('items','i_index',844,17708,14,13); + INSERT INTO sqlite_stat3 VALUES('items','i_index',690,18552,15,14); + INSERT INTO sqlite_stat3 VALUES('items','i_index',655,19242,16,15); + INSERT INTO sqlite_stat3 VALUES('items','i_index',625,19897,17,16); + INSERT INTO sqlite_stat3 VALUES('items','i_index',579,20522,18,17); + INSERT INTO sqlite_stat3 VALUES('items','i_index',555,21101,19,18); + INSERT INTO sqlite_stat3 VALUES('items','i_index',526,21656,20,19); + INSERT INTO sqlite_stat3 VALUES('items','i_index',501,22182,21,20); + INSERT INTO sqlite_stat3 VALUES('items','i_index',459,22683,22,21); + INSERT INTO sqlite_stat3 VALUES('items','i_index',439,23142,23,22); + INSERT INTO sqlite_stat3 VALUES('items','i_index',315,23581,24,23); + INSERT INTO sqlite_stat3 VALUES('items','i_index',192,24177,26,25); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1851,0,0,NULL); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',373,1857,2,'2011-10-22 14:54:39'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',595,2230,3,'2011-10-22 14:54:41'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',337,2825,4,'2011-10-22 14:54:43'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',361,3378,8,'2011-10-22 14:54:54'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',160,3739,9,'2011-10-22 14:54:56'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',315,4000,11,'2011-10-22 14:54:59'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',321,4334,13,'2011-10-22 14:55:02'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1292,4723,16,'2011-10-22 14:55:06'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',161,6015,17,'2011-10-22 14:55:07'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1,9107,2677,'2012-09-04 18:07:50'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',313,9717,3270,'2012-10-18 16:50:21'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',450,10030,3271,'2012-10-18 16:50:22'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',389,10668,3275,'2012-10-18 16:50:26'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',796,11057,3276,'2012-10-18 16:51:06'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',161,12041,3280,'2012-10-19 19:52:37'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',135,13281,4186,'2013-02-19 00:56:10'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1063,13416,4187,'2013-02-19 00:56:11'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',797,14479,4188,'2013-02-19 00:56:13'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',147,15276,4189,'2013-02-19 00:56:15'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',346,15423,4190,'2013-02-19 00:56:16'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1,18215,6436,'2013-05-05 14:09:54'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',2,21251,8122,'2013-05-24 15:25:45'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1,24287,11116,'2013-05-26 14:17:39'); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',2560,0,0,NULL); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',18,3022,31,2350); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',10,6068,285,8150); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',158,6346,315,8949); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',34,9094,562,18831); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',20,12139,794,22838); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',134,14033,886,24739); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',159,14167,887,24740); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,14326,888,24741); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,14487,889,24742); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',124,14648,890,24743); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',157,14772,891,24744); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',126,15043,894,24747); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',40,15169,895,24748); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,15243,898,24753); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',138,15404,899,24754); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',160,15542,900,24755); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,15702,901,24756); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,15863,902,24757); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',124,16024,903,24758); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',155,16148,904,24759); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',26,18208,1043,29704); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',2,21251,1282,32952); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',13,24279,1583,36068); + INSERT INTO sqlite_stat3 VALUES('items','i_secid',25167,0,0,2); + INSERT INTO sqlite_stat3 VALUES('items','i_secid',736,25167,1,3); + INSERT INTO sqlite_stat3 VALUES('items','i_secid',15,25903,2,4); + INSERT INTO sqlite_stat3 VALUES('items','i_secid',1398,25918,3,5); + ANALYZE sqlite_master; + + explain query plan + select items.title + from items + join items as child on child.parent_id=items.id + join items as grandchild on grandchild.parent_id=child.id + join settings + on settings.guid=grandchild.guid + and settings.account_id=1 + where items.metadata_type=2 + and items.secid=2 + and settings.last_viewed_at is not null + group by items.id + order by settings.last_viewed_at desc + limit 10; +} [list \ + 0 0 3 {SEARCH TABLE settings USING INDEX s_account_id (account_id=?)} \ + 0 1 2 {SEARCH TABLE items AS grandchild USING INDEX i_guid (guid=?)} \ + 0 2 1 {SEARCH TABLE items AS child USING INTEGER PRIMARY KEY (rowid=?)} \ + 0 3 0 {SEARCH TABLE items USING INTEGER PRIMARY KEY (rowid=?)} \ + 0 0 0 {USE TEMP B-TREE FOR GROUP BY} \ + 0 0 0 {USE TEMP B-TREE FOR ORDER BY}] + + +finish_test diff --git a/test/win32heap.test b/test/win32heap.test new file mode 100644 index 0000000..b92f804 --- /dev/null +++ b/test/win32heap.test @@ -0,0 +1,74 @@ +# 2013 November 22 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this script is recovery from transient manditory locks +# that sometimes appear on database files due to anti-virus software. +# + +if {$tcl_platform(platform)!="windows"} return + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !win32malloc { + finish_test + return +} + +set testprefix win32heap + +do_test 1.1 { + catch {db close} + sqlite3_shutdown + sqlite3_config_heap_size 1048576 + sqlite3_initialize +} {SQLITE_OK} + +do_test 1.2 { + sqlite3 db test.db + catchsql { + CREATE TABLE t1(x); + } +} {0 {}} + +do_test 1.3 { + catchsql { + INSERT INTO t1 (x) VALUES(RANDOMBLOB(1048576)); + } +} {1 {out of memory}} + +do_test 1.4 { + catchsql { + SELECT COUNT(*) FROM t1; + } +} {0 0} + +do_test 1.5 { + catch {db close} + sqlite3_shutdown + sqlite3_config_heap_size 0 + sqlite3_initialize +} {SQLITE_OK} + +do_test 1.6 { + sqlite3 db test.db + catchsql { + INSERT INTO t1 (x) VALUES(RANDOMBLOB(1048576)); + } +} {0 {}} + +do_test 1.7 { + catchsql { + SELECT COUNT(*) FROM t1; + } +} {0 1} + +finish_test diff --git a/test/win32lock.test b/test/win32lock.test index 7241720..cff1ed3 100644 --- a/test/win32lock.test +++ b/test/win32lock.test @@ -24,7 +24,7 @@ db close sqlite3_shutdown test_sqlite3_log xLog proc xLog {error_code msg} { - lappend ::log $msg + lappend ::log $msg } sqlite3 db test.db db eval {PRAGMA mmap_size=0} @@ -128,7 +128,53 @@ while {1} { file_control_win32_av_retry db 10 25 sqlite3_test_control_pending_byte $old_pending_byte db close +forcedelete test.db + +sqlite3 db test.db +sqlite3 db2 test.db + +do_test win32lock-3.0 { + db eval { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(2); + INSERT INTO t1 VALUES(3); + } +} {} + +do_test win32lock-3.1 { + db eval { + BEGIN EXCLUSIVE; + INSERT INTO t1 VALUES(4); + } +} {} + +do_test win32lock-3.2 { + catchsql { + BEGIN EXCLUSIVE; + INSERT INTO t1 VALUES(5); + COMMIT; + } db2 +} {1 {database is locked}} + +do_test win32lock-3.3 { + db eval { + COMMIT; + } +} {} + +do_test win32lock-3.4 { + set handle [lindex [file_control_win32_set_handle db 0] end] + list [catchsql { + BEGIN EXCLUSIVE; + INSERT INTO t1 VALUES(6); + COMMIT; + }] [file_control_win32_set_handle db $handle] [sqlite3_extended_errcode db] +} {{1 {disk I/O error}} {0 0} SQLITE_IOERR_LOCK} + +db2 close +db close sqlite3_shutdown -test_sqlite3_log +test_sqlite3_log sqlite3_initialize finish_test diff --git a/test/win32longpath.test b/test/win32longpath.test new file mode 100644 index 0000000..9e9ed35 --- /dev/null +++ b/test/win32longpath.test @@ -0,0 +1,110 @@ +# 2013 August 27 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this script is testing the file name handling provided +# by the "win32-longpath" VFS. +# + +if {$tcl_platform(platform)!="windows"} return + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix win32longpath + +do_test 1.0 { + file_control_vfsname db +} win32 + +db close +set path [file nativename [get_pwd]] +sqlite3 db [file join $path test.db] -vfs win32-longpath + +do_test 1.1 { + file_control_vfsname db +} win32-longpath + +do_test 1.2 { + db eval { + BEGIN EXCLUSIVE; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(2); + INSERT INTO t1 VALUES(3); + INSERT INTO t1 VALUES(4); + SELECT x FROM t1 ORDER BY x; + COMMIT; + } +} {1 2 3 4} + +set longPath(1) \\\\?\\$path\\[pid] +make_win32_dir $longPath(1) + +set longPath(2) $longPath(1)\\[string repeat X 255] +make_win32_dir $longPath(2) + +set longPath(3) $longPath(2)\\[string repeat Y 255] +make_win32_dir $longPath(3) + +set fileName $longPath(3)\\test.db + +do_test 1.3 { + list [catch {sqlite3 db2 [string range $fileName 4 end]} msg] $msg +} {1 {unable to open database file}} + +sqlite3 db3 $fileName -vfs win32-longpath + +do_test 1.4 { + db3 eval { + BEGIN EXCLUSIVE; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(5); + INSERT INTO t1 VALUES(6); + INSERT INTO t1 VALUES(7); + INSERT INTO t1 VALUES(8); + SELECT x FROM t1 ORDER BY x; + COMMIT; + } +} {5 6 7 8} + +db3 close +# puts " Database exists \{[exists_win32_path $fileName]\}" + +sqlite3 db3 $fileName -vfs win32-longpath + +do_test 1.5 { + db3 eval { + PRAGMA journal_mode = WAL; + } +} {wal} + +do_test 1.6 { + db3 eval { + BEGIN EXCLUSIVE; + INSERT INTO t1 VALUES(9); + INSERT INTO t1 VALUES(10); + INSERT INTO t1 VALUES(11); + INSERT INTO t1 VALUES(12); + SELECT x FROM t1 ORDER BY x; + COMMIT; + } +} {5 6 7 8 9 10 11 12} + +db3 close +# puts " Database exists \{[exists_win32_path $fileName]\}" + +do_delete_win32_file $fileName +# puts " Files remaining \{[find_win32_file $longPath(3)\\*]\}" + +do_remove_win32_dir $longPath(3) +do_remove_win32_dir $longPath(2) +do_remove_win32_dir $longPath(1) + +finish_test diff --git a/test/with1.test b/test/with1.test new file mode 100644 index 0000000..42d2277 --- /dev/null +++ b/test/with1.test @@ -0,0 +1,831 @@ +# 2014 January 11 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the WITH clause. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix with1 + +ifcapable {!cte} { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE TABLE t1(x INTEGER, y INTEGER); + WITH x(a) AS ( SELECT * FROM t1) SELECT 10 +} {10} + +do_execsql_test 1.1 { + SELECT * FROM ( WITH x AS ( SELECT * FROM t1) SELECT 10 ); +} {10} + +do_execsql_test 1.2 { + WITH x(a) AS ( SELECT * FROM t1) INSERT INTO t1 VALUES(1,2); +} {} + +do_execsql_test 1.3 { + WITH x(a) AS ( SELECT * FROM t1) DELETE FROM t1; +} {} + +do_execsql_test 1.4 { + WITH x(a) AS ( SELECT * FROM t1) UPDATE t1 SET x = y; +} {} + +#-------------------------------------------------------------------------- + +do_execsql_test 2.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(2); + WITH tmp AS ( SELECT * FROM t1 ) SELECT x FROM tmp; +} {1 2} + +do_execsql_test 2.2 { + WITH tmp(a) AS ( SELECT * FROM t1 ) SELECT a FROM tmp; +} {1 2} + +do_execsql_test 2.3 { + SELECT * FROM ( + WITH tmp(a) AS ( SELECT * FROM t1 ) SELECT a FROM tmp + ); +} {1 2} + +do_execsql_test 2.4 { + WITH tmp1(a) AS ( SELECT * FROM t1 ), + tmp2(x) AS ( SELECT * FROM tmp1) + SELECT * FROM tmp2; +} {1 2} + +do_execsql_test 2.5 { + WITH tmp2(x) AS ( SELECT * FROM tmp1), + tmp1(a) AS ( SELECT * FROM t1 ) + SELECT * FROM tmp2; +} {1 2} + +#------------------------------------------------------------------------- +do_catchsql_test 3.1 { + WITH tmp2(x) AS ( SELECT * FROM tmp1 ), + tmp1(a) AS ( SELECT * FROM tmp2 ) + SELECT * FROM tmp1; +} {1 {circular reference: tmp1}} + +do_catchsql_test 3.2 { + CREATE TABLE t2(x INTEGER); + WITH tmp(a) AS (SELECT * FROM t1), + tmp(a) AS (SELECT * FROM t1) + SELECT * FROM tmp; +} {1 {duplicate WITH table name: tmp}} + +do_execsql_test 3.3 { + CREATE TABLE t3(x); + CREATE TABLE t4(x); + + INSERT INTO t3 VALUES('T3'); + INSERT INTO t4 VALUES('T4'); + + WITH t3(a) AS (SELECT * FROM t4) + SELECT * FROM t3; +} {T4} + +do_execsql_test 3.4 { + WITH tmp AS ( SELECT * FROM t3 ), + tmp2 AS ( WITH tmp AS ( SELECT * FROM t4 ) SELECT * FROM tmp ) + SELECT * FROM tmp2; +} {T4} + +do_execsql_test 3.5 { + WITH tmp AS ( SELECT * FROM t3 ), + tmp2 AS ( WITH xxxx AS ( SELECT * FROM t4 ) SELECT * FROM tmp ) + SELECT * FROM tmp2; +} {T3} + +do_catchsql_test 3.6 { + WITH tmp AS ( SELECT * FROM t3 ), + SELECT * FROM tmp; +} {1 {near "SELECT": syntax error}} + +#------------------------------------------------------------------------- +do_execsql_test 4.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(2); + INSERT INTO t1 VALUES(3); + INSERT INTO t1 VALUES(4); + + WITH dset AS ( SELECT 2 UNION ALL SELECT 4 ) + DELETE FROM t1 WHERE x IN dset; + SELECT * FROM t1; +} {1 3} + +do_execsql_test 4.2 { + WITH iset AS ( SELECT 2 UNION ALL SELECT 4 ) + INSERT INTO t1 SELECT * FROM iset; + SELECT * FROM t1; +} {1 3 2 4} + +do_execsql_test 4.3 { + WITH uset(a, b) AS ( SELECT 2, 8 UNION ALL SELECT 4, 9 ) + UPDATE t1 SET x = COALESCE( (SELECT b FROM uset WHERE a=x), x ); + SELECT * FROM t1; +} {1 3 8 9} + +#------------------------------------------------------------------------- +# +do_execsql_test 5.1 { + WITH i(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM i) + SELECT x FROM i LIMIT 10; +} {1 2 3 4 5 6 7 8 9 10} + +do_catchsql_test 5.2 { + WITH i(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM i ORDER BY 1) + SELECT x FROM i LIMIT 10; +} {0 {1 2 3 4 5 6 7 8 9 10}} + +do_execsql_test 5.2.1 { + CREATE TABLE edge(xfrom, xto, seq, PRIMARY KEY(xfrom, xto)) WITHOUT ROWID; + INSERT INTO edge VALUES(0, 1, 10); + INSERT INTO edge VALUES(1, 2, 20); + INSERT INTO edge VALUES(0, 3, 30); + INSERT INTO edge VALUES(2, 4, 40); + INSERT INTO edge VALUES(3, 4, 40); + INSERT INTO edge VALUES(2, 5, 50); + INSERT INTO edge VALUES(3, 6, 60); + INSERT INTO edge VALUES(5, 7, 70); + INSERT INTO edge VALUES(3, 7, 70); + INSERT INTO edge VALUES(4, 8, 80); + INSERT INTO edge VALUES(7, 8, 80); + INSERT INTO edge VALUES(8, 9, 90); + + WITH RECURSIVE + ancest(id, mtime) AS + (VALUES(0, 0) + UNION + SELECT edge.xto, edge.seq FROM edge, ancest + WHERE edge.xfrom=ancest.id + ORDER BY 2 + ) + SELECT * FROM ancest; +} {0 0 1 10 2 20 3 30 4 40 5 50 6 60 7 70 8 80 9 90} +do_execsql_test 5.2.2 { + WITH RECURSIVE + ancest(id, mtime) AS + (VALUES(0, 0) + UNION ALL + SELECT edge.xto, edge.seq FROM edge, ancest + WHERE edge.xfrom=ancest.id + ORDER BY 2 + ) + SELECT * FROM ancest; +} {0 0 1 10 2 20 3 30 4 40 4 40 5 50 6 60 7 70 7 70 8 80 8 80 8 80 8 80 9 90 9 90 9 90 9 90} +do_execsql_test 5.2.3 { + WITH RECURSIVE + ancest(id, mtime) AS + (VALUES(0, 0) + UNION ALL + SELECT edge.xto, edge.seq FROM edge, ancest + WHERE edge.xfrom=ancest.id + ORDER BY 2 LIMIT 4 OFFSET 2 + ) + SELECT * FROM ancest; +} {2 20 3 30 4 40 4 40} + +do_catchsql_test 5.3 { + WITH i(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM i LIMIT 5) + SELECT x FROM i; +} {0 {1 2 3 4 5}} + +do_execsql_test 5.4 { + WITH i(x) AS ( VALUES(1) UNION ALL SELECT (x+1)%10 FROM i) + SELECT x FROM i LIMIT 20; +} {1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0} + +do_execsql_test 5.5 { + WITH i(x) AS ( VALUES(1) UNION SELECT (x+1)%10 FROM i) + SELECT x FROM i LIMIT 20; +} {1 2 3 4 5 6 7 8 9 0} + +do_catchsql_test 5.6.1 { + WITH i(x, y) AS ( VALUES(1) ) + SELECT * FROM i; +} {1 {table i has 1 values for 2 columns}} + +do_catchsql_test 5.6.2 { + WITH i(x) AS ( VALUES(1,2) ) + SELECT * FROM i; +} {1 {table i has 2 values for 1 columns}} + +do_catchsql_test 5.6.3 { + CREATE TABLE t5(a, b); + WITH i(x) AS ( SELECT * FROM t5 ) + SELECT * FROM i; +} {1 {table i has 2 values for 1 columns}} + +do_catchsql_test 5.6.4 { + WITH i(x) AS ( SELECT 1, 2 UNION ALL SELECT 1 ) + SELECT * FROM i; +} {1 {table i has 2 values for 1 columns}} + +do_catchsql_test 5.6.5 { + WITH i(x) AS ( SELECT 1 UNION ALL SELECT 1, 2 ) + SELECT * FROM i; +} {1 {SELECTs to the left and right of UNION ALL do not have the same number of result columns}} + +do_catchsql_test 5.6.6 { + WITH i(x) AS ( SELECT 1 UNION ALL SELECT x+1, x*2 FROM i ) + SELECT * FROM i; +} {1 {SELECTs to the left and right of UNION ALL do not have the same number of result columns}} + +do_catchsql_test 5.6.7 { + WITH i(x) AS ( SELECT 1, 2 UNION SELECT x+1 FROM i ) + SELECT * FROM i; +} {1 {table i has 2 values for 1 columns}} + +#------------------------------------------------------------------------- +# +do_execsql_test 6.1 { + CREATE TABLE f( + id INTEGER PRIMARY KEY, parentid REFERENCES f, name TEXT + ); + + INSERT INTO f VALUES(0, NULL, ''); + INSERT INTO f VALUES(1, 0, 'bin'); + INSERT INTO f VALUES(2, 1, 'true'); + INSERT INTO f VALUES(3, 1, 'false'); + INSERT INTO f VALUES(4, 1, 'ls'); + INSERT INTO f VALUES(5, 1, 'grep'); + INSERT INTO f VALUES(6, 0, 'etc'); + INSERT INTO f VALUES(7, 6, 'rc.d'); + INSERT INTO f VALUES(8, 7, 'rc.apache'); + INSERT INTO f VALUES(9, 7, 'rc.samba'); + INSERT INTO f VALUES(10, 0, 'home'); + INSERT INTO f VALUES(11, 10, 'dan'); + INSERT INTO f VALUES(12, 11, 'public_html'); + INSERT INTO f VALUES(13, 12, 'index.html'); + INSERT INTO f VALUES(14, 13, 'logo.gif'); +} + +do_execsql_test 6.2 { + WITH flat(fid, fpath) AS ( + SELECT id, '' FROM f WHERE parentid IS NULL + UNION ALL + SELECT id, fpath || '/' || name FROM f, flat WHERE parentid=fid + ) + SELECT fpath FROM flat WHERE fpath!='' ORDER BY 1; +} { + /bin + /bin/false /bin/grep /bin/ls /bin/true + /etc + /etc/rc.d + /etc/rc.d/rc.apache /etc/rc.d/rc.samba + /home + /home/dan + /home/dan/public_html + /home/dan/public_html/index.html + /home/dan/public_html/index.html/logo.gif +} + +do_execsql_test 6.3 { + WITH flat(fid, fpath) AS ( + SELECT id, '' FROM f WHERE parentid IS NULL + UNION ALL + SELECT id, fpath || '/' || name FROM f, flat WHERE parentid=fid + ) + SELECT count(*) FROM flat; +} {15} + +do_execsql_test 6.4 { + WITH x(i) AS ( + SELECT 1 + UNION ALL + SELECT i+1 FROM x WHERE i<10 + ) + SELECT count(*) FROM x +} {10} + + +#------------------------------------------------------------------------- + +do_execsql_test 7.1 { + CREATE TABLE tree(i, p); + INSERT INTO tree VALUES(1, NULL); + INSERT INTO tree VALUES(2, 1); + INSERT INTO tree VALUES(3, 1); + INSERT INTO tree VALUES(4, 2); + INSERT INTO tree VALUES(5, 4); +} + +do_execsql_test 7.2 { + WITH t(id, path) AS ( + SELECT i, '' FROM tree WHERE p IS NULL + UNION ALL + SELECT i, path || '/' || i FROM tree, t WHERE p = id + ) + SELECT path FROM t; +} {{} /2 /3 /2/4 /2/4/5} + +do_execsql_test 7.3 { + WITH t(id) AS ( + VALUES(2) + UNION ALL + SELECT i FROM tree, t WHERE p = id + ) + SELECT id FROM t; +} {2 4 5} + +do_catchsql_test 7.4 { + WITH t(id) AS ( + VALUES(2) + UNION ALL + SELECT i FROM tree WHERE p IN (SELECT id FROM t) + ) + SELECT id FROM t; +} {1 {recursive reference in a subquery: t}} + +do_catchsql_test 7.5 { + WITH t(id) AS ( + VALUES(2) + UNION ALL + SELECT i FROM tree, t WHERE p = id AND p IN (SELECT id FROM t) + ) + SELECT id FROM t; +} {1 {multiple recursive references: t}} + +do_catchsql_test 7.6 { + WITH t(id) AS ( + SELECT i FROM tree WHERE 2 IN (SELECT id FROM t) + UNION ALL + SELECT i FROM tree, t WHERE p = id + ) + SELECT id FROM t; +} {1 {circular reference: t}} + +# Compute the mandelbrot set using a recursive query +# +do_execsql_test 8.1-mandelbrot { + WITH RECURSIVE + xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+0.05 FROM xaxis WHERE x<1.2), + yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+0.1 FROM yaxis WHERE y<1.0), + m(iter, cx, cy, x, y) AS ( + SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis + UNION ALL + SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m + WHERE (x*x + y*y) < 4.0 AND iter<28 + ), + m2(iter, cx, cy) AS ( + SELECT max(iter), cx, cy FROM m GROUP BY cx, cy + ), + a(t) AS ( + SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') + FROM m2 GROUP BY cy + ) + SELECT group_concat(rtrim(t),x'0a') FROM a; +} {{ ....# + ..#*.. + ..+####+. + .......+####.... + + ..##+*##########+.++++ + .+.##################+. + .............+###################+.+ + ..++..#.....*#####################+. + ...+#######++#######################. + ....+*################################. + #############################################... + ....+*################################. + ...+#######++#######################. + ..++..#.....*#####################+. + .............+###################+.+ + .+.##################+. + ..##+*##########+.++++ + .......+####.... + + ..+####+. + ..#*.. + ....# + +.}} + +# Solve a sudoku puzzle using a recursive query +# +do_execsql_test 8.2-soduko { + WITH RECURSIVE + input(sud) AS ( + VALUES('53..7....6..195....98....6.8...6...34..8.3..17...2...6.6....28....419..5....8..79') + ), + + /* A table filled with digits 1..9, inclusive. */ + digits(z, lp) AS ( + VALUES('1', 1) + UNION ALL SELECT + CAST(lp+1 AS TEXT), lp+1 FROM digits WHERE lp<9 + ), + + /* The tricky bit. */ + x(s, ind) AS ( + SELECT sud, instr(sud, '.') FROM input + UNION ALL + SELECT + substr(s, 1, ind-1) || z || substr(s, ind+1), + instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' ) + FROM x, digits AS z + WHERE ind>0 + AND NOT EXISTS ( + SELECT 1 + FROM digits AS lp + WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1) + OR z.z = substr(s, ((ind-1)%9) + (lp-1)*9 + 1, 1) + OR z.z = substr(s, (((ind-1)/3) % 3) * 3 + + ((ind-1)/27) * 27 + lp + + ((lp-1) / 3) * 6, 1) + ) + ) + SELECT s FROM x WHERE ind=0; +} {534678912672195348198342567859761423426853791713924856961537284287419635345286179} + +#-------------------------------------------------------------------------- +# Some tests that use LIMIT and OFFSET in the definition of recursive CTEs. +# +set I [list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20] +proc limit_test {tn iLimit iOffset} { + if {$iOffset < 0} { set iOffset 0 } + if {$iLimit < 0 } { + set result [lrange $::I $iOffset end] + } else { + set result [lrange $::I $iOffset [expr $iLimit+$iOffset-1]] + } + uplevel [list do_execsql_test $tn [subst -nocommands { + WITH ii(a) AS ( + VALUES(1) + UNION ALL + SELECT a+1 FROM ii WHERE a<20 + LIMIT $iLimit OFFSET $iOffset + ) + SELECT * FROM ii + }] $result] +} + +limit_test 9.1 20 0 +limit_test 9.2 0 0 +limit_test 9.3 19 1 +limit_test 9.4 20 -1 +limit_test 9.5 5 5 +limit_test 9.6 0 -1 +limit_test 9.7 40 -1 +limit_test 9.8 -1 -1 +limit_test 9.9 -1 -1 + +#-------------------------------------------------------------------------- +# Test the ORDER BY clause on recursive tables. +# + +do_execsql_test 10.1 { + DROP TABLE IF EXISTS tree; + CREATE TABLE tree(id INTEGER PRIMARY KEY, parentid, payload); +} + +proc insert_into_tree {L} { + db eval { DELETE FROM tree } + foreach key $L { + unset -nocomplain parentid + foreach seg [split $key /] { + if {$seg==""} continue + set id [db one { + SELECT id FROM tree WHERE parentid IS $parentid AND payload=$seg + }] + if {$id==""} { + db eval { INSERT INTO tree VALUES(NULL, $parentid, $seg) } + set parentid [db last_insert_rowid] + } else { + set parentid $id + } + } + } +} + +insert_into_tree { + /a/a/a + /a/b/c + /a/b/c/d + /a/b/d +} +do_execsql_test 10.2 { + WITH flat(fid, p) AS ( + SELECT id, '/' || payload FROM tree WHERE parentid IS NULL + UNION ALL + SELECT id, p || '/' || payload FROM flat, tree WHERE parentid=fid + ) + SELECT p FROM flat ORDER BY p; +} { + /a /a/a /a/a/a + /a/b /a/b/c /a/b/c/d + /a/b/d +} + +# Scan the tree-structure currently stored in table tree. Return a list +# of nodes visited. +# +proc scan_tree {bDepthFirst bReverse} { + + set order "ORDER BY " + if {$bDepthFirst==0} { append order "2 ASC," } + if {$bReverse==0} { + append order " 3 ASC" + } else { + append order " 3 DESC" + } + + db eval " + WITH flat(fid, depth, p) AS ( + SELECT id, 1, '/' || payload FROM tree WHERE parentid IS NULL + UNION ALL + SELECT id, depth+1, p||'/'||payload FROM flat, tree WHERE parentid=fid + $order + ) + SELECT p FROM flat; + " +} + +insert_into_tree { + /a/b + /a/b/c + /a/d + /a/d/e + /a/d/f + /g/h +} + +# Breadth first, siblings in ascending order. +# +do_test 10.3 { + scan_tree 0 0 +} [list {*}{ + /a /g + /a/b /a/d /g/h + /a/b/c /a/d/e /a/d/f +}] + +# Depth first, siblings in ascending order. +# +do_test 10.4 { + scan_tree 1 0 +} [list {*}{ + /a /a/b /a/b/c + /a/d /a/d/e + /a/d/f + /g /g/h +}] + +# Breadth first, siblings in descending order. +# +do_test 10.5 { + scan_tree 0 1 +} [list {*}{ + /g /a + /g/h /a/d /a/b + /a/d/f /a/d/e /a/b/c +}] + +# Depth first, siblings in ascending order. +# +do_test 10.6 { + scan_tree 1 1 +} [list {*}{ + /g /g/h + /a /a/d /a/d/f + /a/d/e + /a/b /a/b/c +}] + + +# Test name resolution in ORDER BY clauses. +# +do_catchsql_test 10.7.1 { + WITH t(a) AS ( + SELECT 1 AS b UNION ALL SELECT a+1 AS c FROM t WHERE a<5 ORDER BY a + ) + SELECT * FROM t +} {1 {1st ORDER BY term does not match any column in the result set}} +do_execsql_test 10.7.2 { + WITH t(a) AS ( + SELECT 1 AS b UNION ALL SELECT a+1 AS c FROM t WHERE a<5 ORDER BY b + ) + SELECT * FROM t +} {1 2 3 4 5} +do_execsql_test 10.7.3 { + WITH t(a) AS ( + SELECT 1 AS b UNION ALL SELECT a+1 AS c FROM t WHERE a<5 ORDER BY c + ) + SELECT * FROM t +} {1 2 3 4 5} + +# Test COLLATE clauses attached to ORDER BY. +# +insert_into_tree { + /a/b + /a/C + /a/d + /B/e + /B/F + /B/g + /c/h + /c/I + /c/j +} + +do_execsql_test 10.8.1 { + WITH flat(fid, depth, p) AS ( + SELECT id, 1, '/' || payload FROM tree WHERE parentid IS NULL + UNION ALL + SELECT id, depth+1, p||'/'||payload FROM flat, tree WHERE parentid=fid + ORDER BY 2, 3 COLLATE nocase + ) + SELECT p FROM flat; +} { + /a /B /c + /a/b /a/C /a/d /B/e /B/F /B/g /c/h /c/I /c/j +} +do_execsql_test 10.8.2 { + WITH flat(fid, depth, p) AS ( + SELECT id, 1, ('/' || payload) COLLATE nocase + FROM tree WHERE parentid IS NULL + UNION ALL + SELECT id, depth+1, (p||'/'||payload) + FROM flat, tree WHERE parentid=fid + ORDER BY 2, 3 + ) + SELECT p FROM flat; +} { + /a /B /c + /a/b /a/C /a/d /B/e /B/F /B/g /c/h /c/I /c/j +} + +do_execsql_test 10.8.3 { + WITH flat(fid, depth, p) AS ( + SELECT id, 1, ('/' || payload) + FROM tree WHERE parentid IS NULL + UNION ALL + SELECT id, depth+1, (p||'/'||payload) COLLATE nocase + FROM flat, tree WHERE parentid=fid + ORDER BY 2, 3 + ) + SELECT p FROM flat; +} { + /a /B /c + /a/b /a/C /a/d /B/e /B/F /B/g /c/h /c/I /c/j +} + +do_execsql_test 10.8.4.1 { + CREATE TABLE tst(a,b); + INSERT INTO tst VALUES('a', 'A'); + INSERT INTO tst VALUES('b', 'B'); + INSERT INTO tst VALUES('c', 'C'); + SELECT a COLLATE nocase FROM tst UNION ALL SELECT b FROM tst ORDER BY 1; +} {a A b B c C} +do_execsql_test 10.8.4.2 { + SELECT a FROM tst UNION ALL SELECT b COLLATE nocase FROM tst ORDER BY 1; +} {A B C a b c} +do_execsql_test 10.8.4.3 { + SELECT a||'' FROM tst UNION ALL SELECT b COLLATE nocase FROM tst ORDER BY 1; +} {a A b B c C} + +# Test cases to illustrate on the ORDER BY clause on a recursive query can be +# used to control depth-first versus breath-first search in a tree. +# +do_execsql_test 11.1 { + CREATE TABLE org( + name TEXT PRIMARY KEY, + boss TEXT REFERENCES org + ) WITHOUT ROWID; + INSERT INTO org VALUES('Alice',NULL); + INSERT INTO org VALUES('Bob','Alice'); + INSERT INTO org VALUES('Cindy','Alice'); + INSERT INTO org VALUES('Dave','Bob'); + INSERT INTO org VALUES('Emma','Bob'); + INSERT INTO org VALUES('Fred','Cindy'); + INSERT INTO org VALUES('Gail','Cindy'); + INSERT INTO org VALUES('Harry','Dave'); + INSERT INTO org VALUES('Ingrid','Dave'); + INSERT INTO org VALUES('Jim','Emma'); + INSERT INTO org VALUES('Kate','Emma'); + INSERT INTO org VALUES('Lanny','Fred'); + INSERT INTO org VALUES('Mary','Fred'); + INSERT INTO org VALUES('Noland','Gail'); + INSERT INTO org VALUES('Olivia','Gail'); + -- The above are all under Alice. Add a few more records for people + -- not in Alice's group, just to prove that they won't be selected. + INSERT INTO org VALUES('Xaviar',NULL); + INSERT INTO org VALUES('Xia','Xaviar'); + INSERT INTO org VALUES('Xerxes','Xaviar'); + INSERT INTO org VALUES('Xena','Xia'); + -- Find all members of Alice's group, breath-first order + WITH RECURSIVE + under_alice(name,level) AS ( + VALUES('Alice','0') + UNION ALL + SELECT org.name, under_alice.level+1 + FROM org, under_alice + WHERE org.boss=under_alice.name + ORDER BY 2 + ) + SELECT group_concat(substr('...............',1,level*3) || name,x'0a') + FROM under_alice; +} {{Alice +...Bob +...Cindy +......Dave +......Emma +......Fred +......Gail +.........Harry +.........Ingrid +.........Jim +.........Kate +.........Lanny +.........Mary +.........Noland +.........Olivia}} + +# The previous query used "ORDER BY level" to yield a breath-first search. +# Change that to "ORDER BY level DESC" for a depth-first search. +# +do_execsql_test 11.2 { + WITH RECURSIVE + under_alice(name,level) AS ( + VALUES('Alice','0') + UNION ALL + SELECT org.name, under_alice.level+1 + FROM org, under_alice + WHERE org.boss=under_alice.name + ORDER BY 2 DESC + ) + SELECT group_concat(substr('...............',1,level*3) || name,x'0a') + FROM under_alice; +} {{Alice +...Bob +......Dave +.........Harry +.........Ingrid +......Emma +.........Jim +.........Kate +...Cindy +......Fred +.........Lanny +.........Mary +......Gail +.........Noland +.........Olivia}} + +# Without an ORDER BY clause, the recursive query should use a FIFO, +# resulting in a breath-first search. +# +do_execsql_test 11.3 { + WITH RECURSIVE + under_alice(name,level) AS ( + VALUES('Alice','0') + UNION ALL + SELECT org.name, under_alice.level+1 + FROM org, under_alice + WHERE org.boss=under_alice.name + ) + SELECT group_concat(substr('...............',1,level*3) || name,x'0a') + FROM under_alice; +} {{Alice +...Bob +...Cindy +......Dave +......Emma +......Fred +......Gail +.........Harry +.........Ingrid +.........Jim +.........Kate +.........Lanny +.........Mary +.........Noland +.........Olivia}} + +#-------------------------------------------------------------------------- +# Ticket [31a19d11b97088296ac104aaff113a9790394927] (2014-02-09) +# Name resolution issue with compound SELECTs and Common Table Expressions +# +do_execsql_test 12.1 { +WITH RECURSIVE + t1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM t1 WHERE x<20), + t2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM t2 WHERE y<20) +SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1; +} {2 4 8 10 14 16 20} + + +finish_test diff --git a/test/with2.test b/test/with2.test new file mode 100644 index 0000000..eb06147 --- /dev/null +++ b/test/with2.test @@ -0,0 +1,418 @@ +# 2014 January 11 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the WITH clause. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix with2 + +ifcapable {!cte} { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(2); +} + +do_execsql_test 1.1 { + WITH x1 AS (SELECT * FROM t1) + SELECT sum(a) FROM x1; +} {3} + +do_execsql_test 1.2 { + WITH x1 AS (SELECT * FROM t1) + SELECT (SELECT sum(a) FROM x1); +} {3} + +do_execsql_test 1.3 { + WITH x1 AS (SELECT * FROM t1) + SELECT (SELECT sum(a) FROM x1); +} {3} + +do_execsql_test 1.4 { + CREATE TABLE t2(i); + INSERT INTO t2 VALUES(2); + INSERT INTO t2 VALUES(3); + INSERT INTO t2 VALUES(5); + + WITH x1 AS (SELECT i FROM t2), + i(a) AS ( + SELECT min(i)-1 FROM x1 UNION SELECT a+1 FROM i WHERE a<10 + ) + SELECT a FROM i WHERE a NOT IN x1 +} {1 4 6 7 8 9 10} + +do_execsql_test 1.5 { + WITH x1 AS (SELECT a FROM t1), + x2 AS (SELECT i FROM t2), + x3 AS (SELECT * FROM x1, x2 WHERE x1.a IN x2 AND x2.i IN x1) + SELECT * FROM x3 +} {2 2} + +do_execsql_test 1.6 { + CREATE TABLE t3 AS SELECT 3 AS x; + CREATE TABLE t4 AS SELECT 4 AS x; + + WITH x1 AS (SELECT * FROM t3), + x2 AS ( + WITH t3 AS (SELECT * FROM t4) + SELECT * FROM x1 + ) + SELECT * FROM x2; +} {3} + +do_execsql_test 1.7 { + WITH x2 AS ( + WITH t3 AS (SELECT * FROM t4) + SELECT * FROM t3 + ) + SELECT * FROM x2; +} {4} + +do_execsql_test 1.8 { + WITH x2 AS ( + WITH t3 AS (SELECT * FROM t4) + SELECT * FROM main.t3 + ) + SELECT * FROM x2; +} {3} + +do_execsql_test 1.9 { + WITH x1 AS (SELECT * FROM t1) + SELECT (SELECT sum(a) FROM x1), (SELECT max(a) FROM x1); +} {3 2} + +do_execsql_test 1.10 { + WITH x1 AS (SELECT * FROM t1) + SELECT (SELECT sum(a) FROM x1), (SELECT max(a) FROM x1), a FROM x1; +} {3 2 1 3 2 2} + +do_execsql_test 1.11 { + WITH + i(x) AS ( + WITH + j(x) AS ( SELECT * FROM i ), + i(x) AS ( SELECT * FROM t1 ) + SELECT * FROM j + ) + SELECT * FROM i; +} {1 2} + +do_execsql_test 1.12 { + WITH r(i) AS ( + VALUES('.') + UNION ALL + SELECT i || '.' FROM r, ( + SELECT x FROM x INTERSECT SELECT y FROM y + ) WHERE length(i) < 10 + ), + x(x) AS ( VALUES(1) UNION ALL VALUES(2) UNION ALL VALUES(3) ), + y(y) AS ( VALUES(2) UNION ALL VALUES(4) UNION ALL VALUES(6) ) + + SELECT * FROM r; +} {. .. ... .... ..... ...... ....... ........ ......... ..........} + +do_execsql_test 1.13 { + WITH r(i) AS ( + VALUES('.') + UNION ALL + SELECT i || '.' FROM r, ( SELECT x FROM x WHERE x=2 ) WHERE length(i) < 10 + ), + x(x) AS ( VALUES(1) UNION ALL VALUES(2) UNION ALL VALUES(3) ) + + SELECT * FROM r ORDER BY length(i) DESC; +} {.......... ......... ........ ....... ...... ..... .... ... .. .} + +do_execsql_test 1.14 { + WITH + t4(x) AS ( + VALUES(4) + UNION ALL + SELECT x+1 FROM t4 WHERE x<10 + ) + SELECT * FROM t4; +} {4 5 6 7 8 9 10} + +do_execsql_test 1.15 { + WITH + t4(x) AS ( + VALUES(4) + UNION ALL + SELECT x+1 FROM main.t4 WHERE x<10 + ) + SELECT * FROM t4; +} {4 5} + +do_catchsql_test 1.16 { + WITH + t4(x) AS ( + VALUES(4) + UNION ALL + SELECT x+1 FROM t4, main.t4, t4 WHERE x<10 + ) + SELECT * FROM t4; +} {1 {multiple references to recursive table: t4}} + + +#--------------------------------------------------------------------------- +# Check that variables can be used in CTEs. +# +set ::min [expr 3] +set ::max [expr 9] +do_execsql_test 2.1 { + WITH i(x) AS ( + VALUES($min) UNION ALL SELECT x+1 FROM i WHERE x < $max + ) + SELECT * FROM i; +} {3 4 5 6 7 8 9} + +do_execsql_test 2.2 { + WITH i(x) AS ( + VALUES($min) UNION ALL SELECT x+1 FROM i WHERE x < $max + ) + SELECT x FROM i JOIN i AS j USING (x); +} {3 4 5 6 7 8 9} + +#--------------------------------------------------------------------------- +# Check that circular references are rejected. +# +do_catchsql_test 3.1 { + WITH i(x, y) AS ( VALUES(1, (SELECT x FROM i)) ) + SELECT * FROM i; +} {1 {circular reference: i}} + +do_catchsql_test 3.2 { + WITH + i(x) AS ( SELECT * FROM j ), + j(x) AS ( SELECT * FROM k ), + k(x) AS ( SELECT * FROM i ) + SELECT * FROM i; +} {1 {circular reference: i}} + +do_catchsql_test 3.3 { + WITH + i(x) AS ( SELECT * FROM (SELECT * FROM j) ), + j(x) AS ( SELECT * FROM (SELECT * FROM i) ) + SELECT * FROM i; +} {1 {circular reference: i}} + +do_catchsql_test 3.4 { + WITH + i(x) AS ( SELECT * FROM (SELECT * FROM j) ), + j(x) AS ( SELECT * FROM (SELECT * FROM i) ) + SELECT * FROM j; +} {1 {circular reference: j}} + +do_catchsql_test 3.5 { + WITH + i(x) AS ( + WITH j(x) AS ( SELECT * FROM i ) + SELECT * FROM j + ) + SELECT * FROM i; +} {1 {circular reference: i}} + +#--------------------------------------------------------------------------- +# Try empty and very long column lists. +# +do_catchsql_test 4.1 { + WITH x() AS ( SELECT 1,2,3 ) + SELECT * FROM x; +} {1 {near ")": syntax error}} + +proc genstmt {n} { + for {set i 1} {$i<=$n} {incr i} { + lappend cols "c$i" + lappend vals $i + } + return " + WITH x([join $cols ,]) AS (SELECT [join $vals ,]) + SELECT (c$n == $n) FROM x + " +} + +do_execsql_test 4.2 [genstmt 10] 1 +do_execsql_test 4.3 [genstmt 100] 1 +do_execsql_test 4.4 [genstmt 255] 1 +set nLimit [sqlite3_limit db SQLITE_LIMIT_COLUMN -1] +do_execsql_test 4.5 [genstmt [expr $nLimit-1]] 1 +do_execsql_test 4.6 [genstmt $nLimit] 1 +do_catchsql_test 4.7 [genstmt [expr $nLimit+1]] {1 {too many columns in index}} + +#--------------------------------------------------------------------------- +# Check that adding a WITH clause to an INSERT disables the xfer +# optimization. +# +proc do_xfer_test {tn bXfer sql {res {}}} { + set ::sqlite3_xferopt_count 0 + uplevel [list do_test $tn [subst -nocommands { + set dres [db eval {$sql}] + list [set ::sqlite3_xferopt_count] [set dres] + }] [list $bXfer $res]] +} + +do_execsql_test 5.1 { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1(a, b); + CREATE TABLE t2(a, b); +} + +do_xfer_test 5.2 1 { INSERT INTO t1 SELECT * FROM t2 } +do_xfer_test 5.3 0 { INSERT INTO t1 SELECT a, b FROM t2 } +do_xfer_test 5.4 0 { INSERT INTO t1 SELECT b, a FROM t2 } +do_xfer_test 5.5 0 { + WITH x AS (SELECT a, b FROM t2) INSERT INTO t1 SELECT * FROM x +} +do_xfer_test 5.6 0 { + WITH x AS (SELECT a, b FROM t2) INSERT INTO t1 SELECT * FROM t2 +} +do_xfer_test 5.7 0 { + INSERT INTO t1 WITH x AS ( SELECT * FROM t2 ) SELECT * FROM x +} +do_xfer_test 5.8 0 { + INSERT INTO t1 WITH x(a,b) AS ( SELECT * FROM t2 ) SELECT * FROM x +} + +#--------------------------------------------------------------------------- +# Check that syntax (and other) errors in statements with WITH clauses +# attached to them do not cause problems (e.g. memory leaks). +# +do_execsql_test 6.1 { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1(a, b); + CREATE TABLE t2(a, b); +} + +do_catchsql_test 6.2 { + WITH x AS (SELECT * FROM t1) + INSERT INTO t2 VALUES(1, 2,); +} {1 {near ")": syntax error}} + +do_catchsql_test 6.3 { + WITH x AS (SELECT * FROM t1) + INSERT INTO t2 SELECT a, b, FROM t1; +} {1 {near "FROM": syntax error}} + +do_catchsql_test 6.3 { + WITH x AS (SELECT * FROM t1) + INSERT INTO t2 SELECT a, b FROM abc; +} {1 {no such table: abc}} + +do_catchsql_test 6.4 { + WITH x AS (SELECT * FROM t1) + INSERT INTO t2 SELECT a, b, FROM t1 a a a; +} {1 {near "FROM": syntax error}} + +do_catchsql_test 6.5 { + WITH x AS (SELECT * FROM t1) + DELETE FROM t2 WHERE; +} {1 {near ";": syntax error}} + +do_catchsql_test 6.6 { + WITH x AS (SELECT * FROM t1) DELETE FROM t2 WHERE +} {/1 {near .* syntax error}/} + +do_catchsql_test 6.7 { + WITH x AS (SELECT * FROM t1) DELETE FROM t2 WHRE 1; +} {/1 {near .* syntax error}/} + +do_catchsql_test 6.8 { + WITH x AS (SELECT * FROM t1) UPDATE t2 SET a = 10, b = ; +} {/1 {near .* syntax error}/} + +do_catchsql_test 6.9 { + WITH x AS (SELECT * FROM t1) UPDATE t2 SET a = 10, b = 1 WHERE a===b; +} {/1 {near .* syntax error}/} + +do_catchsql_test 6.10 { + WITH x(a,b) AS ( + SELECT 1, 1 + UNION ALL + SELECT a*b,a+b FROM x WHERE c=2 + ) + SELECT * FROM x +} {1 {no such column: c}} + +#------------------------------------------------------------------------- +# Recursive queries in IN(...) expressions. +# +do_execsql_test 7.1 { + CREATE TABLE t5(x INTEGER); + CREATE TABLE t6(y INTEGER); + + WITH s(x) AS ( VALUES(7) UNION ALL SELECT x+7 FROM s WHERE x<49 ) + INSERT INTO t5 + SELECT * FROM s; + + INSERT INTO t6 + WITH s(x) AS ( VALUES(2) UNION ALL SELECT x+2 FROM s WHERE x<49 ) + SELECT * FROM s; +} + +do_execsql_test 7.2 { + SELECT * FROM t6 WHERE y IN (SELECT x FROM t5) +} {14 28 42} + +do_execsql_test 7.3 { + WITH ss AS (SELECT x FROM t5) + SELECT * FROM t6 WHERE y IN (SELECT x FROM ss) +} {14 28 42} + +do_execsql_test 7.4 { + WITH ss(x) AS ( VALUES(7) UNION ALL SELECT x+7 FROM ss WHERE x<49 ) + SELECT * FROM t6 WHERE y IN (SELECT x FROM ss) +} {14 28 42} + +do_execsql_test 7.5 { + SELECT * FROM t6 WHERE y IN ( + WITH ss(x) AS ( VALUES(7) UNION ALL SELECT x+7 FROM ss WHERE x<49 ) + SELECT x FROM ss + ) +} {14 28 42} + +#------------------------------------------------------------------------- +# At one point the following was causing an assertion failure and a +# memory leak. +# +do_execsql_test 8.1 { + CREATE TABLE t7(y); + INSERT INTO t7 VALUES(NULL); + CREATE VIEW v AS SELECT * FROM t7 ORDER BY y; +} + +do_execsql_test 8.2 { + WITH q(a) AS ( + SELECT 1 + UNION + SELECT a+1 FROM q, v WHERE a<5 + ) + SELECT * FROM q; +} {1 2 3 4 5} + +do_execsql_test 8.3 { + WITH q(a) AS ( + SELECT 1 + UNION ALL + SELECT a+1 FROM q, v WHERE a<5 + ) + SELECT * FROM q; +} {1 2 3 4 5} + + +finish_test + diff --git a/test/withM.test b/test/withM.test new file mode 100644 index 0000000..c1650d9 --- /dev/null +++ b/test/withM.test @@ -0,0 +1,77 @@ +# 2014 January 11 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the WITH clause. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +set ::testprefix withM + +ifcapable {!cte} { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE TABLE t1(x INTEGER, y INTEGER); + INSERT INTO t1 VALUES(123, 456); +} + +do_faultsim_test withM-1.1 -prep { + sqlite3 db test.db +} -body { + execsql { + WITH tmp AS ( SELECT * FROM t1 ) + SELECT * FROM tmp; + } +} -test { + faultsim_test_result {0 {123 456}} + db close +} + +do_faultsim_test withM-1.2 -prep { + sqlite3 db test.db +} -body { + execsql { + WITH w1 AS ( SELECT * FROM t1 ), + w2 AS ( + WITH w3 AS ( SELECT * FROM w1 ) + SELECT * FROM w3 + ) + SELECT * FROM w2; + } +} -test { + faultsim_test_result {0 {123 456}} + db close +} + +do_faultsim_test withM-1.3 -prep { + sqlite3 db test.db +} -body { + execsql { + WITH w1(a,b) AS ( + SELECT 1, 1 + UNION ALL + SELECT a+1, b + 2*a + 1 FROM w1 + ) + SELECT * FROM w1 LIMIT 5; + } +} -test { + faultsim_test_result {0 {1 1 2 4 3 9 4 16 5 25}} + db close +} + +finish_test + + + diff --git a/test/without_rowid1.test b/test/without_rowid1.test new file mode 100644 index 0000000..9d7a643 --- /dev/null +++ b/test/without_rowid1.test @@ -0,0 +1,281 @@ +# 2013-10-30 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements regression tests for SQLite library. The +# focus of this file is testing WITHOUT ROWID tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix without_rowid1 + +# Create and query a WITHOUT ROWID table. +# +do_execsql_test without_rowid1-1.0 { + CREATE TABLE t1(a,b,c,d, PRIMARY KEY(c,a)) WITHOUT ROWID; + CREATE INDEX t1bd ON t1(b, d); + INSERT INTO t1 VALUES('journal','sherman','ammonia','helena'); + INSERT INTO t1 VALUES('dynamic','juliet','flipper','command'); + INSERT INTO t1 VALUES('journal','sherman','gamma','patriot'); + INSERT INTO t1 VALUES('arctic','sleep','ammonia','helena'); + SELECT *, '|' FROM t1 ORDER BY c, a; +} {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic juliet flipper command | journal sherman gamma patriot |} + +integrity_check without_rowid1-1.0ic + +do_execsql_test without_rowid1-1.1 { + SELECT *, '|' FROM t1 ORDER BY +c, a; +} {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic juliet flipper command | journal sherman gamma patriot |} + +do_execsql_test without_rowid1-1.2 { + SELECT *, '|' FROM t1 ORDER BY c DESC, a DESC; +} {journal sherman gamma patriot | dynamic juliet flipper command | journal sherman ammonia helena | arctic sleep ammonia helena |} + +do_execsql_test without_rowid1-1.11 { + SELECT *, '|' FROM t1 ORDER BY b, d; +} {dynamic juliet flipper command | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |} + +do_execsql_test without_rowid1-1.12 { + SELECT *, '|' FROM t1 ORDER BY +b, d; +} {dynamic juliet flipper command | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |} + +# Trying to insert a duplicate PRIMARY KEY fails. +# +do_test without_rowid1-1.21 { + catchsql { + INSERT INTO t1 VALUES('dynamic','phone','flipper','harvard'); + } +} {1 {UNIQUE constraint failed: t1.c, t1.a}} + +# REPLACE INTO works, however. +# +do_execsql_test without_rowid1-1.22 { + REPLACE INTO t1 VALUES('dynamic','phone','flipper','harvard'); + SELECT *, '|' FROM t1 ORDER BY c, a; +} {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic phone flipper harvard | journal sherman gamma patriot |} + +do_execsql_test without_rowid1-1.23 { + SELECT *, '|' FROM t1 ORDER BY b, d; +} {dynamic phone flipper harvard | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |} + +# UPDATE statements. +# +do_execsql_test without_rowid1-1.31 { + UPDATE t1 SET d=3.1415926 WHERE a='journal'; + SELECT *, '|' FROM t1 ORDER BY c, a; +} {arctic sleep ammonia helena | journal sherman ammonia 3.1415926 | dynamic phone flipper harvard | journal sherman gamma 3.1415926 |} +do_execsql_test without_rowid1-1.32 { + SELECT *, '|' FROM t1 ORDER BY b, d; +} {dynamic phone flipper harvard | journal sherman ammonia 3.1415926 | journal sherman gamma 3.1415926 | arctic sleep ammonia helena |} + +do_execsql_test without_rowid1-1.35 { + UPDATE t1 SET a=1250 WHERE b='phone'; + SELECT *, '|' FROM t1 ORDER BY c, a; +} {arctic sleep ammonia helena | journal sherman ammonia 3.1415926 | 1250 phone flipper harvard | journal sherman gamma 3.1415926 |} +integrity_check without_rowid1-1.36 + +do_execsql_test without_rowid1-1.37 { + SELECT *, '|' FROM t1 ORDER BY b, d; +} {1250 phone flipper harvard | journal sherman ammonia 3.1415926 | journal sherman gamma 3.1415926 | arctic sleep ammonia helena |} + +do_execsql_test without_rowid1-1.40 { + VACUUM; + SELECT *, '|' FROM t1 ORDER BY b, d; +} {1250 phone flipper harvard | journal sherman ammonia 3.1415926 | journal sherman gamma 3.1415926 | arctic sleep ammonia helena |} +integrity_check without_rowid1-1.41 + +# Verify that ANALYZE works +# +do_execsql_test without_rowid1-1.50 { + ANALYZE; + SELECT * FROM sqlite_stat1 ORDER BY idx; +} {t1 t1 {4 2 1} t1 t1bd {4 2 2}} +ifcapable stat3 { + do_execsql_test without_rowid1-1.51 { + SELECT DISTINCT tbl, idx FROM sqlite_stat3 ORDER BY idx; + } {t1 t1 t1 t1bd} +} +ifcapable stat4 { + do_execsql_test without_rowid1-1.52 { + SELECT DISTINCT tbl, idx FROM sqlite_stat4 ORDER BY idx; + } {t1 t1 t1 t1bd} +} + +#---------- + +do_execsql_test 2.1.1 { + CREATE TABLE t4 (a COLLATE nocase PRIMARY KEY, b) WITHOUT ROWID; + INSERT INTO t4 VALUES('abc', 'def'); + SELECT * FROM t4; +} {abc def} +do_execsql_test 2.1.2 { + UPDATE t4 SET a = 'ABC'; + SELECT * FROM t4; +} {ABC def} + +do_execsql_test 2.2.1 { + DROP TABLE t4; + CREATE TABLE t4 (b, a COLLATE nocase PRIMARY KEY) WITHOUT ROWID; + INSERT INTO t4(a, b) VALUES('abc', 'def'); + SELECT * FROM t4; +} {def abc} + +do_execsql_test 2.2.2 { + UPDATE t4 SET a = 'ABC', b = 'xyz'; + SELECT * FROM t4; +} {xyz ABC} + +do_execsql_test 2.3.1 { + CREATE TABLE t5 (a, b, PRIMARY KEY(b, a)) WITHOUT ROWID; + INSERT INTO t5(a, b) VALUES('abc', 'def'); + UPDATE t5 SET a='abc', b='def'; +} {} + +do_execsql_test 2.4.1 { + CREATE TABLE t6 ( + a COLLATE nocase, b, c UNIQUE, PRIMARY KEY(b, a) + ) WITHOUT ROWID; + + INSERT INTO t6(a, b, c) VALUES('abc', 'def', 'ghi'); + UPDATE t6 SET a='ABC', c='ghi'; +} {} + +do_execsql_test 2.4.2 { + SELECT * FROM t6 ORDER BY b, a; + SELECT * FROM t6 ORDER BY c; +} {ABC def ghi ABC def ghi} + +#------------------------------------------------------------------------- +# Unless the destination table is completely empty, the xfer optimization +# is disabled for WITHOUT ROWID tables. The following tests check for +# some problems that might occur if this were not the case. +# +reset_db +do_execsql_test 3.1.1 { + CREATE TABLE t1(a, b, PRIMARY KEY(a)) WITHOUT ROWID; + CREATE UNIQUE INDEX i1 ON t1(b); + + CREATE TABLE t2(a, b, PRIMARY KEY(a)) WITHOUT ROWID; + CREATE UNIQUE INDEX i2 ON t2(b); + + INSERT INTO t1 VALUES('one', 'two'); + INSERT INTO t2 VALUES('three', 'two'); +} + +do_execsql_test 3.1.2 { + INSERT OR REPLACE INTO t1 SELECT * FROM t2; + SELECT * FROM t1; +} {three two} + +do_execsql_test 3.1.3 { + DELETE FROM t1; + INSERT INTO t1 SELECT * FROM t2; + SELECT * FROM t1; +} {three two} + +do_catchsql_test 3.1.4 { + INSERT INTO t2 VALUES('four', 'four'); + INSERT INTO t2 VALUES('six', 'two'); + INSERT INTO t1 SELECT * FROM t2; +} {1 {UNIQUE constraint failed: t2.b}} + +do_execsql_test 3.1.5 { + CREATE TABLE t3(a PRIMARY KEY); + CREATE TABLE t4(a PRIMARY KEY); + + INSERT INTO t4 VALUES('i'); + INSERT INTO t4 VALUES('ii'); + INSERT INTO t4 VALUES('iii'); + + INSERT INTO t3 SELECT * FROM t4; + SELECT * FROM t3; +} {i ii iii} + +############################################################################ +# Ticket [c34d0557f740c450709d6e33df72d4f3f651a3cc] +# Name resolution issue with WITHOUT ROWID +# +do_execsql_test 4.1 { + CREATE TABLE t41(a PRIMARY KEY) WITHOUT ROWID; + INSERT INTO t41 VALUES('abc'); + CREATE TABLE t42(x); + INSERT INTO t42 VALUES('xyz'); + SELECT t42.rowid FROM t41, t42; +} {1} +do_execsql_test 4.2 { + SELECT t42.rowid FROM t42, t41; +} {1} + + +#-------------------------------------------------------------------------- +# The following tests verify that the trailing PK fields added to each +# entry in an index on a WITHOUT ROWID table are used correctly. +# +do_execsql_test 5.0 { + CREATE TABLE t45(a PRIMARY KEY, b, c) WITHOUT ROWID; + CREATE INDEX i45 ON t45(b); + + INSERT INTO t45 VALUES(2, 'one', 'x'); + INSERT INTO t45 VALUES(4, 'one', 'x'); + INSERT INTO t45 VALUES(6, 'one', 'x'); + INSERT INTO t45 VALUES(8, 'one', 'x'); + INSERT INTO t45 VALUES(10, 'one', 'x'); + + INSERT INTO t45 VALUES(1, 'two', 'x'); + INSERT INTO t45 VALUES(3, 'two', 'x'); + INSERT INTO t45 VALUES(5, 'two', 'x'); + INSERT INTO t45 VALUES(7, 'two', 'x'); + INSERT INTO t45 VALUES(9, 'two', 'x'); +} + +do_eqp_test 5.1 { + SELECT * FROM t45 WHERE b=? AND a>? +} {/*USING INDEX i45 (b=? AND a>?)*/} + +do_execsql_test 5.2 { + SELECT * FROM t45 WHERE b='two' AND a>4 +} {5 two x 7 two x 9 two x} + +do_execsql_test 5.3 { + SELECT * FROM t45 WHERE b='one' AND a<8 +} { 2 one x 4 one x 6 one x } + +do_execsql_test 5.4 { + CREATE TABLE t46(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID; + WITH r(x) AS ( + SELECT 1 UNION ALL SELECT x+1 FROM r WHERE x<100 + ) + INSERT INTO t46 SELECT x / 20, x % 20, x % 10, x FROM r; +} + +set queries { + 1 2 "c = 5 AND a = 1" {/*i46 (c=? AND a=?)*/} + 2 6 "c = 4 AND a < 3" {/*i46 (c=? AND a<?)*/} + 3 4 "c = 2 AND a >= 3" {/*i46 (c=? AND a>?)*/} + 4 1 "c = 2 AND a = 1 AND b<10" {/*i46 (c=? AND a=? AND b<?)*/} + 5 1 "c = 0 AND a = 0 AND b>5" {/*i46 (c=? AND a=? AND b>?)*/} +} + +foreach {tn cnt where eqp} $queries { + do_execsql_test 5.5.$tn.1 "SELECT count(*) FROM t46 WHERE $where" $cnt +} + +do_execsql_test 5.6 { + CREATE INDEX i46 ON t46(c); +} + +foreach {tn cnt where eqp} $queries { + do_execsql_test 5.7.$tn.1 "SELECT count(*) FROM t46 WHERE $where" $cnt + do_eqp_test 5.7.$tn.2 "SELECT count(*) FROM t46 WHERE $where" $eqp +} + + +finish_test diff --git a/test/without_rowid2.test b/test/without_rowid2.test new file mode 100644 index 0000000..5ba1a23 --- /dev/null +++ b/test/without_rowid2.test @@ -0,0 +1,125 @@ +# 2013-11-02 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements regression tests for SQLite library. The +# focus of this file is testing WITHOUT ROWID tables, and especially +# FOREIGN KEY constraints. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable {!foreignkey} { + finish_test + return +} + +# Create a table and some data to work with. +# +do_test without_rowid2-1.0 { + execsql { + CREATE TABLE t1( + a INT PRIMARY KEY, + b INT + REFERENCES t1 ON DELETE CASCADE + REFERENCES t2, + c TEXT, + FOREIGN KEY (b,c) REFERENCES t2(x,y) ON UPDATE CASCADE + ) WITHOUT rowid; + } +} {} +do_test without_rowid2-1.1 { + execsql { + CREATE TABLE t2( + x INT PRIMARY KEY, + y TEXT + ) WITHOUT rowid; + } +} {} +do_test without_rowid2-1.2 { + execsql { + CREATE TABLE t3( + a INT REFERENCES t2, + b INT REFERENCES t1, + FOREIGN KEY (a,b) REFERENCES t2(x,y) + ); + } +} {} + +do_test without_rowid2-2.1 { + execsql { + CREATE TABLE t4(a int primary key) WITHOUT rowid; + CREATE TABLE t5(x references t4); + CREATE TABLE t6(x references t4); + CREATE TABLE t7(x references t4); + CREATE TABLE t8(x references t4); + CREATE TABLE t9(x references t4); + CREATE TABLE t10(x references t4); + DROP TABLE t7; + DROP TABLE t9; + DROP TABLE t5; + DROP TABLE t8; + DROP TABLE t6; + DROP TABLE t10; + } +} {} + +do_test without_rowid2-3.1 { + execsql { + CREATE TABLE t5(a PRIMARY KEY, b, c) WITHOUT rowid; + CREATE TABLE t6( + d REFERENCES t5, + e REFERENCES t5(c) + ); + PRAGMA foreign_key_list(t6); + } +} [concat \ + {0 0 t5 e c {NO ACTION} {NO ACTION} NONE} \ + {1 0 t5 d {} {NO ACTION} {NO ACTION} NONE} \ +] +do_test without_rowid2-3.2 { + execsql { + CREATE TABLE t7(d, e, f, + FOREIGN KEY (d, e) REFERENCES t5(a, b) + ); + PRAGMA foreign_key_list(t7); + } +} [concat \ + {0 0 t5 d a {NO ACTION} {NO ACTION} NONE} \ + {0 1 t5 e b {NO ACTION} {NO ACTION} NONE} \ +] +do_test without_rowid2-3.3 { + execsql { + CREATE TABLE t8(d, e, f, + FOREIGN KEY (d, e) REFERENCES t5 ON DELETE CASCADE ON UPDATE SET NULL + ); + PRAGMA foreign_key_list(t8); + } +} [concat \ + {0 0 t5 d {} {SET NULL} CASCADE NONE} \ + {0 1 t5 e {} {SET NULL} CASCADE NONE} \ +] +do_test without_rowid2-3.4 { + execsql { + CREATE TABLE t9(d, e, f, + FOREIGN KEY (d, e) REFERENCES t5 ON DELETE CASCADE ON UPDATE SET DEFAULT + ); + PRAGMA foreign_key_list(t9); + } +} [concat \ + {0 0 t5 d {} {SET DEFAULT} CASCADE NONE} \ + {0 1 t5 e {} {SET DEFAULT} CASCADE NONE} \ +] +do_test without_rowid2-3.5 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 0 0} + +finish_test diff --git a/test/without_rowid3.test b/test/without_rowid3.test new file mode 100644 index 0000000..c4c2d6f --- /dev/null +++ b/test/without_rowid3.test @@ -0,0 +1,2084 @@ +# 2013-11-02 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests for foreign keys on WITHOUT ROWID +# tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable {!foreignkey||!trigger} { + finish_test + return +} + +#------------------------------------------------------------------------- +# Test structure: +# +# without_rowid3-1.*: Simple tests to check that immediate and deferred foreign key +# constraints work when not inside a transaction. +# +# without_rowid3-2.*: Tests to verify that deferred foreign keys work inside +# explicit transactions (i.e that processing really is deferred). +# +# without_rowid3-3.*: Tests that a statement transaction is rolled back if an +# immediate foreign key constraint is violated. +# +# without_rowid3-4.*: Test that FK actions may recurse even when recursive triggers +# are disabled. +# +# without_rowid3-5.*: Check that if foreign-keys are enabled, it is not possible +# to write to an FK column using the incremental blob API. +# +# without_rowid3-6.*: Test that FK processing is automatically disabled when +# running VACUUM. +# +# without_rowid3-7.*: Test using an IPK as the key in the child (referencing) table. +# +# without_rowid3-8.*: Test that enabling/disabling foreign key support while a +# transaction is active is not possible. +# +# without_rowid3-9.*: Test SET DEFAULT actions. +# +# without_rowid3-10.*: Test errors. +# +# without_rowid3-11.*: Test CASCADE actions. +# +# without_rowid3-12.*: Test RESTRICT actions. +# +# without_rowid3-13.*: Test that FK processing is performed when a row is REPLACED by +# an UPDATE or INSERT statement. +# +# without_rowid3-14.*: Test the ALTER TABLE and DROP TABLE commands. +# +# without_rowid3-15.*: Test that if there are no (known) outstanding foreign key +# constraint violations in the database, inserting into a parent +# table or deleting from a child table does not cause SQLite +# to check if this has repaired an outstanding violation. +# +# without_rowid3-16.*: Test that rows that refer to themselves may be inserted, +# updated and deleted. +# +# without_rowid3-17.*: Test that the "count_changes" pragma does not interfere with +# FK constraint processing. +# +# without_rowid3-18.*: Test that the authorization callback is invoked when processing +# FK constraints. +# +# without_rowid3-20.*: Test that ON CONFLICT clauses specified as part of statements +# do not affect the operation of FK constraints. +# +# without_rowid3-genfkey.*: Tests that were used with the shell tool .genfkey +# command. Recycled to test the built-in implementation. +# +# without_rowid3-dd08e5.*: Tests to verify that ticket dd08e5a988d00decc4a543daa8d +# has been fixed. +# + + +execsql { PRAGMA foreign_keys = on } + +set FkeySimpleSchema { + PRAGMA foreign_keys = on; + CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE t2(c REFERENCES t1(a) /D/ , d); + + CREATE TABLE t3(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE t4(c REFERENCES t3 /D/, d); + + CREATE TABLE t7(a, b INT PRIMARY KEY) WITHOUT rowid; + CREATE TABLE t8(c REFERENCES t7 /D/, d); + + CREATE TABLE t9(a REFERENCES nosuchtable, b); + CREATE TABLE t10(a REFERENCES t9(c) /D/, b); +} + + +set FkeySimpleTests { + 1.1 "INSERT INTO t2 VALUES(1, 3)" {1 {FOREIGN KEY constraint failed}} + 1.2 "INSERT INTO t1 VALUES(1, 2)" {0 {}} + 1.3 "INSERT INTO t2 VALUES(1, 3)" {0 {}} + 1.4 "INSERT INTO t2 VALUES(2, 4)" {1 {FOREIGN KEY constraint failed}} + 1.5 "INSERT INTO t2 VALUES(NULL, 4)" {0 {}} + 1.6 "UPDATE t2 SET c=2 WHERE d=4" {1 {FOREIGN KEY constraint failed}} + 1.7 "UPDATE t2 SET c=1 WHERE d=4" {0 {}} + 1.9 "UPDATE t2 SET c=1 WHERE d=4" {0 {}} + 1.10 "UPDATE t2 SET c=NULL WHERE d=4" {0 {}} + 1.11 "DELETE FROM t1 WHERE a=1" {1 {FOREIGN KEY constraint failed}} + 1.12 "UPDATE t1 SET a = 2" {1 {FOREIGN KEY constraint failed}} + 1.13 "UPDATE t1 SET a = 1" {0 {}} + + 2.1 "INSERT INTO t4 VALUES(1, 3)" {1 {FOREIGN KEY constraint failed}} + 2.2 "INSERT INTO t3 VALUES(1, 2)" {0 {}} + 2.3 "INSERT INTO t4 VALUES(1, 3)" {0 {}} + + 4.1 "INSERT INTO t8 VALUES(1, 3)" {1 {FOREIGN KEY constraint failed}} + 4.2 "INSERT INTO t7 VALUES(2, 1)" {0 {}} + 4.3 "INSERT INTO t8 VALUES(1, 3)" {0 {}} + 4.4 "INSERT INTO t8 VALUES(2, 4)" {1 {FOREIGN KEY constraint failed}} + 4.5 "INSERT INTO t8 VALUES(NULL, 4)" {0 {}} + 4.6 "UPDATE t8 SET c=2 WHERE d=4" {1 {FOREIGN KEY constraint failed}} + 4.7 "UPDATE t8 SET c=1 WHERE d=4" {0 {}} + 4.9 "UPDATE t8 SET c=1 WHERE d=4" {0 {}} + 4.10 "UPDATE t8 SET c=NULL WHERE d=4" {0 {}} + 4.11 "DELETE FROM t7 WHERE b=1" {1 {FOREIGN KEY constraint failed}} + 4.12 "UPDATE t7 SET b = 2" {1 {FOREIGN KEY constraint failed}} + 4.13 "UPDATE t7 SET b = 1" {0 {}} + 4.14 "INSERT INTO t8 VALUES('a', 'b')" {1 {FOREIGN KEY constraint failed}} + 4.15 "UPDATE t7 SET b = 5" {1 {FOREIGN KEY constraint failed}} + 4.17 "UPDATE t7 SET a = 10" {0 {}} + + 5.1 "INSERT INTO t9 VALUES(1, 3)" {1 {no such table: main.nosuchtable}} + 5.2 "INSERT INTO t10 VALUES(1, 3)" + {1 {foreign key mismatch - "t10" referencing "t9"}} +} + +do_test without_rowid3-1.1.0 { + execsql [string map {/D/ {}} $FkeySimpleSchema] +} {} +foreach {tn zSql res} $FkeySimpleTests { + do_test without_rowid3-1.1.$tn.1 { catchsql $zSql } $res + do_test without_rowid3-1.1.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {} + do_test without_rowid3-1.1.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {} + do_test without_rowid3-1.1.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {} + do_test without_rowid3-1.1.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {} + do_test without_rowid3-1.1.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {} + do_test without_rowid3-1.1.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {} +} +drop_all_tables + +do_test without_rowid3-1.2.0 { + execsql [string map {/D/ {DEFERRABLE INITIALLY DEFERRED}} $FkeySimpleSchema] +} {} +foreach {tn zSql res} $FkeySimpleTests { + do_test without_rowid3-1.2.$tn { catchsql $zSql } $res + do_test without_rowid3-1.2.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {} + do_test without_rowid3-1.2.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {} + do_test without_rowid3-1.2.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {} + do_test without_rowid3-1.2.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {} + do_test without_rowid3-1.2.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {} + do_test without_rowid3-1.2.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {} +} +drop_all_tables + +do_test without_rowid3-1.3.0 { + execsql [string map {/D/ {}} $FkeySimpleSchema] + execsql { PRAGMA count_changes = 1 } +} {} +foreach {tn zSql res} $FkeySimpleTests { + if {$res == "0 {}"} { set res {0 1} } + do_test without_rowid3-1.3.$tn { catchsql $zSql } $res + do_test without_rowid3-1.3.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {} + do_test without_rowid3-1.3.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {} + do_test without_rowid3-1.3.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {} + do_test without_rowid3-1.3.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {} + do_test without_rowid3-1.3.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {} + do_test without_rowid3-1.3.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {} +} +execsql { PRAGMA count_changes = 0 } +drop_all_tables + +do_test without_rowid3-1.4.0 { + execsql [string map {/D/ {}} $FkeySimpleSchema] + execsql { PRAGMA count_changes = 1 } +} {} +foreach {tn zSql res} $FkeySimpleTests { + if {$res == "0 {}"} { set res {0 1} } + execsql BEGIN + do_test without_rowid3-1.4.$tn { catchsql $zSql } $res + execsql COMMIT +} +execsql { PRAGMA count_changes = 0 } +drop_all_tables + +# Special test: When the parent key is an IPK, make sure the affinity of +# the IPK is not applied to the child key value before it is inserted +# into the child table. +do_test without_rowid3-1.5.1 { + execsql { + CREATE TABLE i(i INT PRIMARY KEY) WITHOUT rowid; + CREATE TABLE j(j REFERENCES i); + INSERT INTO i VALUES(35); + INSERT INTO j VALUES('35.0'); + SELECT j, typeof(j) FROM j; + } +} {35.0 text} +do_test without_rowid3-1.5.2 { + catchsql { DELETE FROM i } +} {1 {FOREIGN KEY constraint failed}} + +# Same test using a regular primary key with integer affinity. +drop_all_tables +do_test without_rowid3-1.6.1 { + execsql { + CREATE TABLE i(i INT UNIQUE); + CREATE TABLE j(j REFERENCES i(i)); + INSERT INTO i VALUES('35.0'); + INSERT INTO j VALUES('35.0'); + SELECT j, typeof(j) FROM j; + SELECT i, typeof(i) FROM i; + } +} {35.0 text 35 integer} +do_test without_rowid3-1.6.2 { + catchsql { DELETE FROM i } +} {1 {FOREIGN KEY constraint failed}} + +# Use a collation sequence on the parent key. +drop_all_tables +do_test without_rowid3-1.7.1 { + execsql { + CREATE TABLE i(i TEXT COLLATE nocase PRIMARY KEY) WITHOUT rowid; + CREATE TABLE j(j TEXT COLLATE binary REFERENCES i(i)); + INSERT INTO i VALUES('SQLite'); + INSERT INTO j VALUES('sqlite'); + } + catchsql { DELETE FROM i } +} {1 {FOREIGN KEY constraint failed}} + +# Use the parent key collation even if it is default and the child key +# has an explicit value. +drop_all_tables +do_test without_rowid3-1.7.2 { + execsql { + CREATE TABLE i(i TEXT PRIMARY KEY) WITHOUT rowid; -- Colseq is "BINARY" + CREATE TABLE j(j TEXT COLLATE nocase REFERENCES i(i)); + INSERT INTO i VALUES('SQLite'); + } + catchsql { INSERT INTO j VALUES('sqlite') } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-1.7.3 { + execsql { + INSERT INTO i VALUES('sqlite'); + INSERT INTO j VALUES('sqlite'); + DELETE FROM i WHERE i = 'SQLite'; + } + catchsql { DELETE FROM i WHERE i = 'sqlite' } +} {1 {FOREIGN KEY constraint failed}} + +#------------------------------------------------------------------------- +# This section (test cases without_rowid3-2.*) contains tests to check that the +# deferred foreign key constraint logic works. +# +proc without_rowid3-2-test {tn nocommit sql {res {}}} { + if {$res eq "FKV"} { + set expected {1 {FOREIGN KEY constraint failed}} + } else { + set expected [list 0 $res] + } + do_test without_rowid3-2.$tn [list catchsql $sql] $expected + if {$nocommit} { + do_test without_rowid3-2.${tn}c { + catchsql COMMIT + } {1 {FOREIGN KEY constraint failed}} + } +} + +without_rowid3-2-test 1 0 { + CREATE TABLE node( + nodeid PRIMARY KEY, + parent REFERENCES node DEFERRABLE INITIALLY DEFERRED + ) WITHOUT rowid; + CREATE TABLE leaf( + cellid PRIMARY KEY, + parent REFERENCES node DEFERRABLE INITIALLY DEFERRED + ) WITHOUT rowid; +} + +without_rowid3-2-test 1 0 "INSERT INTO node VALUES(1, 0)" FKV +without_rowid3-2-test 2 0 "BEGIN" +without_rowid3-2-test 3 1 "INSERT INTO node VALUES(1, 0)" +without_rowid3-2-test 4 0 "UPDATE node SET parent = NULL" +without_rowid3-2-test 5 0 "COMMIT" +without_rowid3-2-test 6 0 "SELECT * FROM node" {1 {}} + +without_rowid3-2-test 7 0 "BEGIN" +without_rowid3-2-test 8 1 "INSERT INTO leaf VALUES('a', 2)" +without_rowid3-2-test 9 1 "INSERT INTO node VALUES(2, 0)" +without_rowid3-2-test 10 0 "UPDATE node SET parent = 1 WHERE nodeid = 2" +without_rowid3-2-test 11 0 "COMMIT" +without_rowid3-2-test 12 0 "SELECT * FROM node" {1 {} 2 1} +without_rowid3-2-test 13 0 "SELECT * FROM leaf" {a 2} + +without_rowid3-2-test 14 0 "BEGIN" +without_rowid3-2-test 15 1 "DELETE FROM node WHERE nodeid = 2" +without_rowid3-2-test 16 0 "INSERT INTO node VALUES(2, NULL)" +without_rowid3-2-test 17 0 "COMMIT" +without_rowid3-2-test 18 0 "SELECT * FROM node" {1 {} 2 {}} +without_rowid3-2-test 19 0 "SELECT * FROM leaf" {a 2} + +without_rowid3-2-test 20 0 "BEGIN" +without_rowid3-2-test 21 0 "INSERT INTO leaf VALUES('b', 1)" +without_rowid3-2-test 22 0 "SAVEPOINT save" +without_rowid3-2-test 23 0 "DELETE FROM node WHERE nodeid = 1" +without_rowid3-2-test 24 0 "ROLLBACK TO save" +without_rowid3-2-test 25 0 "COMMIT" +without_rowid3-2-test 26 0 "SELECT * FROM node" {1 {} 2 {}} +without_rowid3-2-test 27 0 "SELECT * FROM leaf" {a 2 b 1} + +without_rowid3-2-test 28 0 "BEGIN" +without_rowid3-2-test 29 0 "INSERT INTO leaf VALUES('c', 1)" +without_rowid3-2-test 30 0 "SAVEPOINT save" +without_rowid3-2-test 31 0 "DELETE FROM node WHERE nodeid = 1" +without_rowid3-2-test 32 1 "RELEASE save" +without_rowid3-2-test 33 1 "DELETE FROM leaf WHERE cellid = 'b'" +without_rowid3-2-test 34 0 "DELETE FROM leaf WHERE cellid = 'c'" +without_rowid3-2-test 35 0 "COMMIT" +without_rowid3-2-test 36 0 "SELECT * FROM node" {2 {}} +without_rowid3-2-test 37 0 "SELECT * FROM leaf" {a 2} + +without_rowid3-2-test 38 0 "SAVEPOINT outer" +without_rowid3-2-test 39 1 "INSERT INTO leaf VALUES('d', 3)" +without_rowid3-2-test 40 1 "RELEASE outer" FKV +without_rowid3-2-test 41 1 "INSERT INTO leaf VALUES('e', 3)" +without_rowid3-2-test 42 0 "INSERT INTO node VALUES(3, 2)" +without_rowid3-2-test 43 0 "RELEASE outer" + +without_rowid3-2-test 44 0 "SAVEPOINT outer" +without_rowid3-2-test 45 1 "DELETE FROM node WHERE nodeid=3" +without_rowid3-2-test 47 0 "INSERT INTO node VALUES(3, 2)" +without_rowid3-2-test 48 0 "ROLLBACK TO outer" +without_rowid3-2-test 49 0 "RELEASE outer" + +without_rowid3-2-test 50 0 "SAVEPOINT outer" +without_rowid3-2-test 51 1 "INSERT INTO leaf VALUES('f', 4)" +without_rowid3-2-test 52 1 "SAVEPOINT inner" +without_rowid3-2-test 53 1 "INSERT INTO leaf VALUES('g', 4)" +without_rowid3-2-test 54 1 "RELEASE outer" FKV +without_rowid3-2-test 55 1 "ROLLBACK TO inner" +without_rowid3-2-test 56 0 "COMMIT" FKV +without_rowid3-2-test 57 0 "INSERT INTO node VALUES(4, NULL)" +without_rowid3-2-test 58 0 "RELEASE outer" +without_rowid3-2-test 59 0 "SELECT * FROM node" {2 {} 3 2 4 {}} +without_rowid3-2-test 60 0 "SELECT * FROM leaf" {a 2 d 3 e 3 f 4} + +# The following set of tests check that if a statement that affects +# multiple rows violates some foreign key constraints, then strikes a +# constraint that causes the statement-transaction to be rolled back, +# the deferred constraint counter is correctly reset to the value it +# had before the statement-transaction was opened. +# +without_rowid3-2-test 61 0 "BEGIN" +without_rowid3-2-test 62 0 "DELETE FROM leaf" +without_rowid3-2-test 63 0 "DELETE FROM node" +without_rowid3-2-test 64 1 "INSERT INTO leaf VALUES('a', 1)" +without_rowid3-2-test 65 1 "INSERT INTO leaf VALUES('b', 2)" +without_rowid3-2-test 66 1 "INSERT INTO leaf VALUES('c', 1)" +do_test without_rowid3-2-test-67 { + catchsql "INSERT INTO node SELECT parent, 3 FROM leaf" +} {1 {UNIQUE constraint failed: node.nodeid}} +without_rowid3-2-test 68 0 "COMMIT" FKV +without_rowid3-2-test 69 1 "INSERT INTO node VALUES(1, NULL)" +without_rowid3-2-test 70 0 "INSERT INTO node VALUES(2, NULL)" +without_rowid3-2-test 71 0 "COMMIT" + +without_rowid3-2-test 72 0 "BEGIN" +without_rowid3-2-test 73 1 "DELETE FROM node" +without_rowid3-2-test 74 0 "INSERT INTO node(nodeid) SELECT DISTINCT parent FROM leaf" +without_rowid3-2-test 75 0 "COMMIT" + +#------------------------------------------------------------------------- +# Test cases without_rowid3-3.* test that a program that executes foreign key +# actions (CASCADE, SET DEFAULT, SET NULL etc.) or tests FK constraints +# opens a statement transaction if required. +# +# without_rowid3-3.1.*: Test UPDATE statements. +# without_rowid3-3.2.*: Test DELETE statements. +# +drop_all_tables +do_test without_rowid3-3.1.1 { + execsql { + CREATE TABLE ab(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE cd( + c PRIMARY KEY REFERENCES ab ON UPDATE CASCADE ON DELETE CASCADE, + d + ) WITHOUT rowid; + CREATE TABLE ef( + e REFERENCES cd ON UPDATE CASCADE, + f, CHECK (e!=5) + ); + } +} {} +do_test without_rowid3-3.1.2 { + execsql { + INSERT INTO ab VALUES(1, 'b'); + INSERT INTO cd VALUES(1, 'd'); + INSERT INTO ef VALUES(1, 'e'); + } +} {} +do_test without_rowid3-3.1.3 { + catchsql { UPDATE ab SET a = 5 } +} {1 {CHECK constraint failed: ef}} +do_test without_rowid3-3.1.4 { + execsql { SELECT * FROM ab } +} {1 b} +do_test without_rowid3-3.1.4 { + execsql BEGIN; + catchsql { UPDATE ab SET a = 5 } +} {1 {CHECK constraint failed: ef}} +do_test without_rowid3-3.1.5 { + execsql COMMIT; + execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef } +} {1 b 1 d 1 e} + +do_test without_rowid3-3.2.1 { + execsql BEGIN; + catchsql { DELETE FROM ab } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-3.2.2 { + execsql COMMIT + execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef } +} {1 b 1 d 1 e} + +#------------------------------------------------------------------------- +# Test cases without_rowid3-4.* test that recursive foreign key actions +# (i.e. CASCADE) are allowed even if recursive triggers are disabled. +# +drop_all_tables +do_test without_rowid3-4.1 { + execsql { + CREATE TABLE t1( + node PRIMARY KEY, + parent REFERENCES t1 ON DELETE CASCADE + ) WITHOUT rowid; + CREATE TABLE t2(node PRIMARY KEY, parent) WITHOUT rowid; + CREATE TRIGGER t2t AFTER DELETE ON t2 BEGIN + DELETE FROM t2 WHERE parent = old.node; + END; + INSERT INTO t1 VALUES(1, NULL); + INSERT INTO t1 VALUES(2, 1); + INSERT INTO t1 VALUES(3, 1); + INSERT INTO t1 VALUES(4, 2); + INSERT INTO t1 VALUES(5, 2); + INSERT INTO t1 VALUES(6, 3); + INSERT INTO t1 VALUES(7, 3); + INSERT INTO t2 SELECT * FROM t1; + } +} {} +do_test without_rowid3-4.2 { + execsql { PRAGMA recursive_triggers = off } + execsql { + BEGIN; + DELETE FROM t1 WHERE node = 1; + SELECT node FROM t1; + } +} {} +do_test without_rowid3-4.3 { + execsql { + DELETE FROM t2 WHERE node = 1; + SELECT node FROM t2; + ROLLBACK; + } +} {4 5 6 7} +do_test without_rowid3-4.4 { + execsql { PRAGMA recursive_triggers = on } + execsql { + BEGIN; + DELETE FROM t1 WHERE node = 1; + SELECT node FROM t1; + } +} {} +do_test without_rowid3-4.3 { + execsql { + DELETE FROM t2 WHERE node = 1; + SELECT node FROM t2; + ROLLBACK; + } +} {} + +#------------------------------------------------------------------------- +# Test cases without_rowid3-5.* verify that the incremental blob API may not +# write to a foreign key column while foreign-keys are enabled. +# +drop_all_tables +ifcapable incrblob { + do_test without_rowid3-5.1 { + execsql { + CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1(a)) WITHOUT rowid; + INSERT INTO t1 VALUES('hello', 'world'); + INSERT INTO t2 VALUES('key', 'hello'); + } + } {} + do_test without_rowid3-5.2 { + set rc [catch { set fd [db incrblob t2 b 1] } msg] + list $rc $msg + } {1 {cannot open table without rowid: t2}} + do_test without_rowid3-5.5 { + execsql { PRAGMA foreign_keys = on } + } {} +} + +drop_all_tables +ifcapable vacuum { + do_test without_rowid3-6.1 { + execsql { + CREATE TABLE t1(a REFERENCES t2(c), b); + CREATE TABLE t2(c UNIQUE, b); + INSERT INTO t2 VALUES(1, 2); + INSERT INTO t1 VALUES(1, 2); + VACUUM; + } + } {} +} + +#------------------------------------------------------------------------- +# Test that it is possible to use an INT PRIMARY KEY as the child key +# of a foreign constraint. +# +drop_all_tables +do_test without_rowid3-7.1 { + execsql { + CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE t2(c INT PRIMARY KEY REFERENCES t1, b) WITHOUT rowid; + } +} {} +do_test without_rowid3-7.2 { + catchsql { INSERT INTO t2 VALUES(1, 'A'); } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-7.3 { + execsql { + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(2, 3); + INSERT INTO t2 VALUES(1, 'A'); + } +} {} +do_test without_rowid3-7.4 { + execsql { UPDATE t2 SET c = 2 } +} {} +do_test without_rowid3-7.5 { + catchsql { UPDATE t2 SET c = 3 } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-7.6 { + catchsql { DELETE FROM t1 WHERE a = 2 } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-7.7 { + execsql { DELETE FROM t1 WHERE a = 1 } +} {} +do_test without_rowid3-7.8 { + catchsql { UPDATE t1 SET a = 3 } +} {1 {FOREIGN KEY constraint failed}} + +#------------------------------------------------------------------------- +# Test that it is not possible to enable/disable FK support while a +# transaction is open. +# +drop_all_tables +proc without_rowid3-8-test {tn zSql value} { + do_test without_rowid3-2.8.$tn.1 [list execsql $zSql] {} + do_test without_rowid3-2.8.$tn.2 { execsql "PRAGMA foreign_keys" } $value +} +without_rowid3-8-test 1 { PRAGMA foreign_keys = 0 } 0 +without_rowid3-8-test 2 { PRAGMA foreign_keys = 1 } 1 +without_rowid3-8-test 3 { BEGIN } 1 +without_rowid3-8-test 4 { PRAGMA foreign_keys = 0 } 1 +without_rowid3-8-test 5 { COMMIT } 1 +without_rowid3-8-test 6 { PRAGMA foreign_keys = 0 } 0 +without_rowid3-8-test 7 { BEGIN } 0 +without_rowid3-8-test 8 { PRAGMA foreign_keys = 1 } 0 +without_rowid3-8-test 9 { COMMIT } 0 +without_rowid3-8-test 10 { PRAGMA foreign_keys = 1 } 1 +without_rowid3-8-test 11 { PRAGMA foreign_keys = off } 0 +without_rowid3-8-test 12 { PRAGMA foreign_keys = on } 1 +without_rowid3-8-test 13 { PRAGMA foreign_keys = no } 0 +without_rowid3-8-test 14 { PRAGMA foreign_keys = yes } 1 +without_rowid3-8-test 15 { PRAGMA foreign_keys = false } 0 +without_rowid3-8-test 16 { PRAGMA foreign_keys = true } 1 + +#------------------------------------------------------------------------- +# The following tests, without_rowid3-9.*, test SET DEFAULT actions. +# +drop_all_tables +do_test without_rowid3-9.1.1 { + execsql { + CREATE TABLE t1(a INT PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE t2( + c INT PRIMARY KEY, + d INTEGER DEFAULT 1 REFERENCES t1 ON DELETE SET DEFAULT + ) WITHOUT rowid; + DELETE FROM t1; + } +} {} +do_test without_rowid3-9.1.2 { + execsql { + INSERT INTO t1 VALUES(1, 'one'); + INSERT INTO t1 VALUES(2, 'two'); + INSERT INTO t2 VALUES(1, 2); + SELECT * FROM t2; + DELETE FROM t1 WHERE a = 2; + SELECT * FROM t2; + } +} {1 2 1 1} +do_test without_rowid3-9.1.3 { + execsql { + INSERT INTO t1 VALUES(2, 'two'); + UPDATE t2 SET d = 2; + DELETE FROM t1 WHERE a = 1; + SELECT * FROM t2; + } +} {1 2} +do_test without_rowid3-9.1.4 { + execsql { SELECT * FROM t1 } +} {2 two} +do_test without_rowid3-9.1.5 { + catchsql { DELETE FROM t1 } +} {1 {FOREIGN KEY constraint failed}} + +do_test without_rowid3-9.2.1 { + execsql { + CREATE TABLE pp(a, b, c, PRIMARY KEY(b, c)) WITHOUT rowid; + CREATE TABLE cc(d DEFAULT 3, e DEFAULT 1, f DEFAULT 2, + FOREIGN KEY(f, d) REFERENCES pp + ON UPDATE SET DEFAULT + ON DELETE SET NULL + ); + INSERT INTO pp VALUES(1, 2, 3); + INSERT INTO pp VALUES(4, 5, 6); + INSERT INTO pp VALUES(7, 8, 9); + } +} {} +do_test without_rowid3-9.2.2 { + execsql { + INSERT INTO cc VALUES(6, 'A', 5); + INSERT INTO cc VALUES(6, 'B', 5); + INSERT INTO cc VALUES(9, 'A', 8); + INSERT INTO cc VALUES(9, 'B', 8); + UPDATE pp SET b = 1 WHERE a = 7; + SELECT * FROM cc; + } +} {6 A 5 6 B 5 3 A 2 3 B 2} +do_test without_rowid3-9.2.3 { + execsql { + DELETE FROM pp WHERE a = 4; + SELECT * FROM cc; + } +} {{} A {} {} B {} 3 A 2 3 B 2} + +#------------------------------------------------------------------------- +# The following tests, without_rowid3-10.*, test "foreign key mismatch" and +# other errors. +# +set tn 0 +foreach zSql [list { + CREATE TABLE p(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE c(x REFERENCES p(c)); +} { + CREATE TABLE c(x REFERENCES v(y)); + CREATE VIEW v AS SELECT x AS y FROM c; +} { + CREATE TABLE p(a, b, PRIMARY KEY(a, b)) WITHOUT rowid; + CREATE TABLE c(x REFERENCES p); +} { + CREATE TABLE p(a COLLATE binary, b); + CREATE UNIQUE INDEX i ON p(a COLLATE nocase); + CREATE TABLE c(x REFERENCES p(a)); +}] { + drop_all_tables + do_test without_rowid3-10.1.[incr tn] { + execsql $zSql + catchsql { INSERT INTO c DEFAULT VALUES } + } {/1 {foreign key mismatch - "c" referencing "."}/} +} + +# "rowid" cannot be used as part of a child or parent key definition +# unless it happens to be the name of an explicitly declared column. +# +do_test without_rowid3-10.2.1 { + drop_all_tables + catchsql { + CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE t2(c, d, FOREIGN KEY(rowid) REFERENCES t1(a)); + } +} {1 {unknown column "rowid" in foreign key definition}} +do_test without_rowid3-10.2.2 { + drop_all_tables + catchsql { + CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE t2(rowid, d, FOREIGN KEY(rowid) REFERENCES t1(a)); + } +} {0 {}} +do_test without_rowid3-10.2.1 { + drop_all_tables + catchsql { + CREATE TABLE t1(a, b); + CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(rowid)); + INSERT INTO t1(rowid, a, b) VALUES(1, 1, 1); + INSERT INTO t2 VALUES(1, 1); + } +} {1 {foreign key mismatch - "t2" referencing "t1"}} +do_test without_rowid3-10.2.2 { + drop_all_tables + catchsql { + CREATE TABLE t1(rowid PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(rowid)); + INSERT INTO t1(rowid, b) VALUES(1, 1); + INSERT INTO t2 VALUES(1, 1); + } +} {0 {}} + + +#------------------------------------------------------------------------- +# The following tests, without_rowid3-11.*, test CASCADE actions. +# +drop_all_tables +do_test without_rowid3-11.1.1 { + execsql { + CREATE TABLE t1(a INT PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(a) ON UPDATE CASCADE); + + INSERT INTO t1 VALUES(10, 100); + INSERT INTO t2 VALUES(10, 100); + UPDATE t1 SET a = 15; + SELECT * FROM t2; + } +} {15 100} + +#------------------------------------------------------------------------- +# The following tests, without_rowid3-12.*, test RESTRICT actions. +# +drop_all_tables +do_test without_rowid3-12.1.1 { + execsql { + CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT rowid; + CREATE TABLE t2( + x REFERENCES t1 ON UPDATE RESTRICT DEFERRABLE INITIALLY DEFERRED + ); + INSERT INTO t1 VALUES(1, 'one'); + INSERT INTO t1 VALUES(2, 'two'); + INSERT INTO t1 VALUES(3, 'three'); + } +} {} +do_test without_rowid3-12.1.2 { + execsql "BEGIN" + execsql "INSERT INTO t2 VALUES('two')" +} {} +do_test without_rowid3-12.1.3 { + execsql "UPDATE t1 SET b = 'four' WHERE b = 'one'" +} {} +do_test without_rowid3-12.1.4 { + catchsql "UPDATE t1 SET b = 'five' WHERE b = 'two'" +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-12.1.5 { + execsql "DELETE FROM t1 WHERE b = 'two'" +} {} +do_test without_rowid3-12.1.6 { + catchsql "COMMIT" +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-12.1.7 { + execsql { + INSERT INTO t1 VALUES(2, 'two'); + COMMIT; + } +} {} + +drop_all_tables +do_test without_rowid3-12.2.1 { + execsql { + CREATE TABLE t1(x COLLATE NOCASE PRIMARY KEY) WITHOUT rowid; + CREATE TRIGGER tt1 AFTER DELETE ON t1 + WHEN EXISTS ( SELECT 1 FROM t2 WHERE old.x = y ) + BEGIN + INSERT INTO t1 VALUES(old.x); + END; + CREATE TABLE t2(y REFERENCES t1); + INSERT INTO t1 VALUES('A'); + INSERT INTO t1 VALUES('B'); + INSERT INTO t2 VALUES('a'); + INSERT INTO t2 VALUES('b'); + + SELECT * FROM t1; + SELECT * FROM t2; + } +} {A B a b} +do_test without_rowid3-12.2.2 { + execsql { DELETE FROM t1 } + execsql { + SELECT * FROM t1; + SELECT * FROM t2; + } +} {A B a b} +do_test without_rowid3-12.2.3 { + execsql { + DROP TABLE t2; + CREATE TABLE t2(y REFERENCES t1 ON DELETE RESTRICT); + INSERT INTO t2 VALUES('a'); + INSERT INTO t2 VALUES('b'); + } + catchsql { DELETE FROM t1 } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-12.2.4 { + execsql { + SELECT * FROM t1; + SELECT * FROM t2; + } +} {A B a b} + +drop_all_tables +do_test without_rowid3-12.3.1 { + execsql { + CREATE TABLE up( + c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, + c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, + c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, + c30, c31, c32, c33, c34, c35, c36, c37, c38, c39, + PRIMARY KEY(c34, c35) + ) WITHOUT rowid; + CREATE TABLE down( + c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, + c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, + c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, + c30, c31, c32, c33, c34, c35, c36, c37, c38, c39, + FOREIGN KEY(c39, c38) REFERENCES up ON UPDATE CASCADE + ); + } +} {} +do_test without_rowid3-12.3.2 { + execsql { + INSERT INTO up(c34, c35) VALUES('yes', 'no'); + INSERT INTO down(c39, c38) VALUES('yes', 'no'); + UPDATE up SET c34 = 'possibly'; + SELECT c38, c39 FROM down; + DELETE FROM down; + } +} {no possibly} +do_test without_rowid3-12.3.3 { + catchsql { INSERT INTO down(c39, c38) VALUES('yes', 'no') } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-12.3.4 { + execsql { + INSERT INTO up(c34, c35) VALUES('yes', 'no'); + INSERT INTO down(c39, c38) VALUES('yes', 'no'); + } + catchsql { DELETE FROM up WHERE c34 = 'yes' } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-12.3.5 { + execsql { + DELETE FROM up WHERE c34 = 'possibly'; + SELECT c34, c35 FROM up; + SELECT c39, c38 FROM down; + } +} {yes no yes no} + +#------------------------------------------------------------------------- +# The following tests, without_rowid3-13.*, test that FK processing is performed +# when rows are REPLACEd. +# +drop_all_tables +do_test without_rowid3-13.1.1 { + execsql { + CREATE TABLE pp(a UNIQUE, b, c, PRIMARY KEY(b, c)) WITHOUT rowid; + CREATE TABLE cc(d, e, f UNIQUE, FOREIGN KEY(d, e) REFERENCES pp); + INSERT INTO pp VALUES(1, 2, 3); + INSERT INTO cc VALUES(2, 3, 1); + } +} {} +foreach {tn stmt} { + 1 "REPLACE INTO pp VALUES(1, 4, 5)" +} { + do_test without_rowid3-13.1.$tn.1 { + catchsql $stmt + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-13.1.$tn.2 { + execsql { + SELECT * FROM pp; + SELECT * FROM cc; + } + } {1 2 3 2 3 1} + do_test without_rowid3-13.1.$tn.3 { + execsql BEGIN; + catchsql $stmt + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-13.1.$tn.4 { + execsql { + COMMIT; + SELECT * FROM pp; + SELECT * FROM cc; + } + } {1 2 3 2 3 1} +} + +#------------------------------------------------------------------------- +# The following tests, without_rowid3-14.*, test that the "DROP TABLE" and "ALTER +# TABLE" commands work as expected wrt foreign key constraints. +# +# without_rowid3-14.1*: ALTER TABLE ADD COLUMN +# without_rowid3-14.2*: ALTER TABLE RENAME TABLE +# without_rowid3-14.3*: DROP TABLE +# +drop_all_tables +ifcapable altertable { + do_test without_rowid3-14.1.1 { + # Adding a column with a REFERENCES clause is not supported. + execsql { + CREATE TABLE t1(a PRIMARY KEY) WITHOUT rowid; + CREATE TABLE t2(a, b); + } + catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } + } {0 {}} + do_test without_rowid3-14.1.2 { + catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } + } {0 {}} + do_test without_rowid3-14.1.3 { + catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} + } {0 {}} + do_test without_rowid3-14.1.4 { + catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'} + } {1 {Cannot add a REFERENCES column with non-NULL default value}} + do_test without_rowid3-14.1.5 { + catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 } + } {1 {Cannot add a REFERENCES column with non-NULL default value}} + do_test without_rowid3-14.1.6 { + execsql { + PRAGMA foreign_keys = off; + ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; + PRAGMA foreign_keys = on; + SELECT sql FROM sqlite_master WHERE name='t2'; + } + } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} + + + # Test the sqlite_rename_parent() function directly. + # + proc test_rename_parent {zCreate zOld zNew} { + db eval {SELECT sqlite_rename_parent($zCreate, $zOld, $zNew)} + } + do_test without_rowid3-14.2.1.1 { + test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 + } {{CREATE TABLE t1(a REFERENCES "t3")}} + do_test without_rowid3-14.2.1.2 { + test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 + } {{CREATE TABLE t1(a REFERENCES t2)}} + do_test without_rowid3-14.2.1.3 { + test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3 + } {{CREATE TABLE t1(a REFERENCES "t3")}} + + # Test ALTER TABLE RENAME TABLE a bit. + # + do_test without_rowid3-14.2.2.1 { + drop_all_tables + execsql { + CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid; + CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) + WITHOUT rowid; + CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1); + } + execsql { SELECT sql FROM sqlite_master WHERE type = 'table'} + } [list \ + {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \ + {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) + WITHOUT rowid} \ + {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \ + ] + do_test without_rowid3-14.2.2.2 { + execsql { ALTER TABLE t1 RENAME TO t4 } + execsql { SELECT sql FROM sqlite_master WHERE type = 'table'} + } [list \ + {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \ + {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2) + WITHOUT rowid} \ + {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \ + ] + do_test without_rowid3-14.2.2.3 { + catchsql { INSERT INTO t3 VALUES(1, 2, 3) } + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-14.2.2.4 { + execsql { INSERT INTO t4 VALUES(1, NULL) } + } {} + do_test without_rowid3-14.2.2.5 { + catchsql { UPDATE t4 SET b = 5 } + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-14.2.2.6 { + catchsql { UPDATE t4 SET b = 1 } + } {0 {}} + do_test without_rowid3-14.2.2.7 { + execsql { INSERT INTO t3 VALUES(1, NULL, 1) } + } {} + + # Repeat for TEMP tables + # + drop_all_tables + do_test without_rowid3-14.1tmp.1 { + # Adding a column with a REFERENCES clause is not supported. + execsql { + CREATE TEMP TABLE t1(a PRIMARY KEY) WITHOUT rowid; + CREATE TEMP TABLE t2(a, b); + } + catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } + } {0 {}} + do_test without_rowid3-14.1tmp.2 { + catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } + } {0 {}} + do_test without_rowid3-14.1tmp.3 { + catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} + } {0 {}} + do_test without_rowid3-14.1tmp.4 { + catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'} + } {1 {Cannot add a REFERENCES column with non-NULL default value}} + do_test without_rowid3-14.1tmp.5 { + catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 } + } {1 {Cannot add a REFERENCES column with non-NULL default value}} + do_test without_rowid3-14.1tmp.6 { + execsql { + PRAGMA foreign_keys = off; + ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; + PRAGMA foreign_keys = on; + SELECT sql FROM sqlite_temp_master WHERE name='t2'; + } + } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} + + do_test without_rowid3-14.2tmp.1.1 { + test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 + } {{CREATE TABLE t1(a REFERENCES "t3")}} + do_test without_rowid3-14.2tmp.1.2 { + test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 + } {{CREATE TABLE t1(a REFERENCES t2)}} + do_test without_rowid3-14.2tmp.1.3 { + test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3 + } {{CREATE TABLE t1(a REFERENCES "t3")}} + + # Test ALTER TABLE RENAME TABLE a bit. + # + do_test without_rowid3-14.2tmp.2.1 { + drop_all_tables + execsql { + CREATE TEMP TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid; + CREATE TEMP TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) + WITHOUT rowid; + CREATE TEMP TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1); + } + execsql { SELECT sql FROM sqlite_temp_master WHERE type = 'table'} + } [list \ + {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \ + {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) + WITHOUT rowid} \ + {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \ + ] + do_test without_rowid3-14.2tmp.2.2 { + execsql { ALTER TABLE t1 RENAME TO t4 } + execsql { SELECT sql FROM sqlite_temp_master WHERE type = 'table'} + } [list \ + {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \ + {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2) + WITHOUT rowid} \ + {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \ + ] + do_test without_rowid3-14.2tmp.2.3 { + catchsql { INSERT INTO t3 VALUES(1, 2, 3) } + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-14.2tmp.2.4 { + execsql { INSERT INTO t4 VALUES(1, NULL) } + } {} + do_test without_rowid3-14.2tmp.2.5 { + catchsql { UPDATE t4 SET b = 5 } + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-14.2tmp.2.6 { + catchsql { UPDATE t4 SET b = 1 } + } {0 {}} + do_test without_rowid3-14.2tmp.2.7 { + execsql { INSERT INTO t3 VALUES(1, NULL, 1) } + } {} + + # Repeat for ATTACH-ed tables + # + drop_all_tables + do_test without_rowid3-14.1aux.1 { + # Adding a column with a REFERENCES clause is not supported. + execsql { + ATTACH ':memory:' AS aux; + CREATE TABLE aux.t1(a PRIMARY KEY) WITHOUT rowid; + CREATE TABLE aux.t2(a, b); + } + catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } + } {0 {}} + do_test without_rowid3-14.1aux.2 { + catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } + } {0 {}} + do_test without_rowid3-14.1aux.3 { + catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} + } {0 {}} + do_test without_rowid3-14.1aux.4 { + catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'} + } {1 {Cannot add a REFERENCES column with non-NULL default value}} + do_test without_rowid3-14.1aux.5 { + catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 } + } {1 {Cannot add a REFERENCES column with non-NULL default value}} + do_test without_rowid3-14.1aux.6 { + execsql { + PRAGMA foreign_keys = off; + ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; + PRAGMA foreign_keys = on; + SELECT sql FROM aux.sqlite_master WHERE name='t2'; + } + } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} + + do_test without_rowid3-14.2aux.1.1 { + test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 + } {{CREATE TABLE t1(a REFERENCES "t3")}} + do_test without_rowid3-14.2aux.1.2 { + test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 + } {{CREATE TABLE t1(a REFERENCES t2)}} + do_test without_rowid3-14.2aux.1.3 { + test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3 + } {{CREATE TABLE t1(a REFERENCES "t3")}} + + # Test ALTER TABLE RENAME TABLE a bit. + # + do_test without_rowid3-14.2aux.2.1 { + drop_all_tables + execsql { + CREATE TABLE aux.t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid; + CREATE TABLE aux.t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) + WITHOUT rowid; + CREATE TABLE aux.t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1); + } + execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'} + } [list \ + {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \ + {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) + WITHOUT rowid} \ + {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \ + ] + do_test without_rowid3-14.2aux.2.2 { + execsql { ALTER TABLE t1 RENAME TO t4 } + execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'} + } [list \ + {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \ + {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2) + WITHOUT rowid} \ + {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \ + ] + do_test without_rowid3-14.2aux.2.3 { + catchsql { INSERT INTO t3 VALUES(1, 2, 3) } + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-14.2aux.2.4 { + execsql { INSERT INTO t4 VALUES(1, NULL) } + } {} + do_test without_rowid3-14.2aux.2.5 { + catchsql { UPDATE t4 SET b = 5 } + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-14.2aux.2.6 { + catchsql { UPDATE t4 SET b = 1 } + } {0 {}} + do_test without_rowid3-14.2aux.2.7 { + execsql { INSERT INTO t3 VALUES(1, NULL, 1) } + } {} +} + +do_test without_rowid3-2.14.3.1 { + drop_all_tables + execsql { + CREATE TABLE t1(a, b REFERENCES nosuchtable); + DROP TABLE t1; + } +} {} +do_test without_rowid3-2.14.3.2 { + execsql { + CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT rowid; + INSERT INTO t1 VALUES('a', 1); + CREATE TABLE t2(x REFERENCES t1); + INSERT INTO t2 VALUES('a'); + } +} {} +do_test without_rowid3-2.14.3.3 { + catchsql { DROP TABLE t1 } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-2.14.3.4 { + execsql { + DELETE FROM t2; + DROP TABLE t1; + } +} {} +do_test without_rowid3-2.14.3.4 { + catchsql { INSERT INTO t2 VALUES('x') } +} {1 {no such table: main.t1}} +do_test without_rowid3-2.14.3.5 { + execsql { + CREATE TABLE t1(x PRIMARY KEY) WITHOUT rowid; + INSERT INTO t1 VALUES('x'); + } + execsql { INSERT INTO t2 VALUES('x') } +} {} +do_test without_rowid3-2.14.3.6 { + catchsql { DROP TABLE t1 } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-2.14.3.7 { + execsql { + DROP TABLE t2; + DROP TABLE t1; + } +} {} +do_test without_rowid3-2.14.3.8 { + execsql { + CREATE TABLE pp(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID; + CREATE TABLE cc(a, b, FOREIGN KEY(a, b) REFERENCES pp(x, z)); + } + catchsql { INSERT INTO cc VALUES(1, 2) } +} {1 {foreign key mismatch - "cc" referencing "pp"}} +do_test without_rowid3-2.14.3.9 { + execsql { DROP TABLE cc } +} {} +do_test without_rowid3-2.14.3.10 { + execsql { + CREATE TABLE cc(a, b, + FOREIGN KEY(a, b) REFERENCES pp DEFERRABLE INITIALLY DEFERRED + ); + } + execsql { + INSERT INTO pp VALUES('a', 'b'); + INSERT INTO cc VALUES('a', 'b'); + BEGIN; + DROP TABLE pp; + CREATE TABLE pp(a, b, c, PRIMARY KEY(b, c)) WITHOUT rowid; + INSERT INTO pp VALUES(1, 'a', 'b'); + COMMIT; + } +} {} +do_test without_rowid3-2.14.3.11 { + execsql { + BEGIN; + DROP TABLE cc; + DROP TABLE pp; + COMMIT; + } +} {} +do_test without_rowid3-2.14.3.12 { + execsql { + CREATE TABLE b1(a, b); + CREATE TABLE b2(a, b REFERENCES b1); + DROP TABLE b1; + } +} {} +do_test without_rowid3-2.14.3.13 { + execsql { + CREATE TABLE b3(a, b REFERENCES b2 DEFERRABLE INITIALLY DEFERRED); + DROP TABLE b2; + } +} {} + +# Test that nothing goes wrong when dropping a table that refers to a view. +# Or dropping a view that an existing FK (incorrectly) refers to. Or either +# of the above scenarios with a virtual table. +drop_all_tables +do_test without_rowid3-2.14.4.1 { + execsql { + CREATE TABLE t1(x REFERENCES v); + CREATE VIEW v AS SELECT * FROM t1; + } +} {} +do_test without_rowid3-2.14.4.2 { + execsql { + DROP VIEW v; + } +} {} +ifcapable vtab { + register_echo_module db + do_test without_rowid3-2.14.4.3 { + execsql { CREATE VIRTUAL TABLE v USING echo(t1) } + } {} + do_test without_rowid3-2.14.4.2 { + execsql { + DROP TABLE v; + } + } {} +} + +#------------------------------------------------------------------------- +# The following tests, without_rowid3-15.*, test that unnecessary FK related scans +# and lookups are avoided when the constraint counters are zero. +# +drop_all_tables +proc execsqlS {zSql} { + set ::sqlite_search_count 0 + set ::sqlite_found_count 0 + set res [uplevel [list execsql $zSql]] + concat [expr $::sqlite_found_count + $::sqlite_search_count] $res +} +do_test without_rowid3-15.1.1 { + execsql { + CREATE TABLE pp(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE cc(x, y REFERENCES pp DEFERRABLE INITIALLY DEFERRED); + INSERT INTO pp VALUES(1, 'one'); + INSERT INTO pp VALUES(2, 'two'); + INSERT INTO cc VALUES('neung', 1); + INSERT INTO cc VALUES('song', 2); + } +} {} +do_test without_rowid3-15.1.2 { + execsqlS { INSERT INTO pp VALUES(3, 'three') } +} {0} +do_test without_rowid3-15.1.3 { + execsql { + BEGIN; + INSERT INTO cc VALUES('see', 4); -- Violates deferred constraint + } + execsqlS { INSERT INTO pp VALUES(5, 'five') } +} {2} +do_test without_rowid3-15.1.4 { + execsql { DELETE FROM cc WHERE x = 'see' } + execsqlS { INSERT INTO pp VALUES(6, 'six') } +} {0} +do_test without_rowid3-15.1.5 { + execsql COMMIT +} {} +do_test without_rowid3-15.1.6 { + execsql BEGIN + execsqlS { + DELETE FROM cc WHERE x = 'neung'; + ROLLBACK; + } +} {1} +do_test without_rowid3-15.1.7 { + execsql { + BEGIN; + DELETE FROM pp WHERE a = 2; + } + execsqlS { + DELETE FROM cc WHERE x = 'neung'; + ROLLBACK; + } +} {2} + +#------------------------------------------------------------------------- +# This next block of tests, without_rowid3-16.*, test that rows that refer to +# themselves may be inserted and deleted. +# +foreach {tn zSchema} { + 1 { CREATE TABLE self(a INTEGER PRIMARY KEY, b REFERENCES self(a)) + WITHOUT rowid } + 2 { CREATE TABLE self(a PRIMARY KEY, b REFERENCES self(a)) WITHOUT rowid } + 3 { CREATE TABLE self(a UNIQUE, b INT PRIMARY KEY REFERENCES self(a)) + WITHOUT rowid } +} { + drop_all_tables + do_test without_rowid3-16.1.$tn.1 { + execsql $zSchema + execsql { INSERT INTO self VALUES(13, 13) } + } {} + do_test without_rowid3-16.1.$tn.2 { + execsql { UPDATE self SET a = 14, b = 14 } + } {} + + do_test without_rowid3-16.1.$tn.3 { + catchsql { UPDATE self SET b = 15 } + } {1 {FOREIGN KEY constraint failed}} + + do_test without_rowid3-16.1.$tn.4 { + catchsql { UPDATE self SET a = 15 } + } {1 {FOREIGN KEY constraint failed}} + + do_test without_rowid3-16.1.$tn.5 { + catchsql { UPDATE self SET a = 15, b = 16 } + } {1 {FOREIGN KEY constraint failed}} + + do_test without_rowid3-16.1.$tn.6 { + catchsql { UPDATE self SET a = 17, b = 17 } + } {0 {}} + + do_test without_rowid3-16.1.$tn.7 { + execsql { DELETE FROM self } + } {} + do_test without_rowid3-16.1.$tn.8 { + catchsql { INSERT INTO self VALUES(20, 21) } + } {1 {FOREIGN KEY constraint failed}} +} + +# Additional tests cases using multi-column self-referential +# FOREIGN KEY constraints. +# +drop_all_tables +do_execsql_test without_rowid3-16.4.1.1 { + PRAGMA foreign_keys=ON; + CREATE TABLE t1(a,b,c,d,e,f, + UNIQUE (a,b), + PRIMARY KEY (e,c), + FOREIGN KEY (d,f) REFERENCES t1(e,c) + ) WITHOUT rowid; + INSERT INTO t1 VALUES(1,2,3,5,5,3); + INSERT INTO t1 VALUES(2,3,4,6,6,4); + INSERT INTO t1 VALUES('x','y',1.5,'fizzle','fizzle',1.5); + SELECT *, '|' FROM t1 ORDER BY a, b; +} {1 2 3 5 5 3 | 2 3 4 6 6 4 | x y 1.5 fizzle fizzle 1.5 |} + +do_execsql_test without_rowid3-16.4.1.2 { + UPDATE t1 SET c=99, f=99 WHERE a=1; + SELECT *, '|' FROM t1 ORDER BY a, b; +} {1 2 99 5 5 99 | 2 3 4 6 6 4 | x y 1.5 fizzle fizzle 1.5 |} + +do_execsql_test without_rowid3-16.4.1.3 { + UPDATE t1 SET e=876, d=876 WHERE a=2; + SELECT *, '|' FROM t1 ORDER BY a, b; +} {1 2 99 5 5 99 | 2 3 4 876 876 4 | x y 1.5 fizzle fizzle 1.5 |} + +do_test without_rowid3-16.4.1.4 { + catchsql { + UPDATE t1 SET c=11, e=22 WHERE a=1; + } +} {1 {FOREIGN KEY constraint failed}} + +do_test without_rowid3-16.4.1.5 { + catchsql { + UPDATE t1 SET d=11, f=22 WHERE a=1; + } +} {1 {FOREIGN KEY constraint failed}} + +do_execsql_test without_rowid3-16.4.1.6 { + DELETE FROM t1 WHERE a=1; + SELECT *, '|' FROM t1 ORDER BY a, b; +} {2 3 4 876 876 4 | x y 1.5 fizzle fizzle 1.5 |} + +do_execsql_test without_rowid3-16.4.2.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e,f, + PRIMARY KEY (a,b), + UNIQUE (e,c), + FOREIGN KEY (d,f) REFERENCES t1(e,c) + ) WITHOUT rowid; + INSERT INTO t1 VALUES(1,2,3,5,5,3); + INSERT INTO t1 VALUES(2,3,4,6,6,4); + INSERT INTO t1 VALUES('x','y',1.5,'fizzle','fizzle',1.5); + SELECT *, '|' FROM t1 ORDER BY a, b; +} {1 2 3 5 5 3 | 2 3 4 6 6 4 | x y 1.5 fizzle fizzle 1.5 |} + +do_execsql_test without_rowid3-16.4.2.2 { + UPDATE t1 SET c=99, f=99 WHERE a=1; + SELECT *, '|' FROM t1 ORDER BY a, b; +} {1 2 99 5 5 99 | 2 3 4 6 6 4 | x y 1.5 fizzle fizzle 1.5 |} + +do_execsql_test without_rowid3-16.4.2.3 { + UPDATE t1 SET e=876, d=876 WHERE a=2; + SELECT *, '|' FROM t1 ORDER BY a, b; +} {1 2 99 5 5 99 | 2 3 4 876 876 4 | x y 1.5 fizzle fizzle 1.5 |} + +do_test without_rowid3-16.4.2.4 { + catchsql { + UPDATE t1 SET c=11, e=22 WHERE a=1; + } +} {1 {FOREIGN KEY constraint failed}} + +do_test without_rowid3-16.4.2.5 { + catchsql { + UPDATE t1 SET d=11, f=22 WHERE a=1; + } +} {1 {FOREIGN KEY constraint failed}} + +do_execsql_test without_rowid3-16.4.2.6 { + DELETE FROM t1 WHERE a=1; + SELECT *, '|' FROM t1 ORDER BY a, b; +} {2 3 4 876 876 4 | x y 1.5 fizzle fizzle 1.5 |} + + +#------------------------------------------------------------------------- +# This next block of tests, without_rowid3-17.*, tests that if "PRAGMA count_changes" +# is turned on statements that violate immediate FK constraints return +# SQLITE_CONSTRAINT immediately, not after returning a number of rows. +# Whereas statements that violate deferred FK constraints return the number +# of rows before failing. +# +# Also test that rows modified by FK actions are not counted in either the +# returned row count or the values returned by sqlite3_changes(). Like +# trigger related changes, they are included in sqlite3_total_changes() though. +# +drop_all_tables +do_test without_rowid3-17.1.1 { + execsql { PRAGMA count_changes = 1 } + execsql { + CREATE TABLE one(a, b, c, UNIQUE(b, c)); + CREATE TABLE two(d, e, f, FOREIGN KEY(e, f) REFERENCES one(b, c)); + INSERT INTO one VALUES(1, 2, 3); + } +} {1} +do_test without_rowid3-17.1.2 { + set STMT [sqlite3_prepare_v2 db "INSERT INTO two VALUES(4, 5, 6)" -1 dummy] + sqlite3_step $STMT +} {SQLITE_CONSTRAINT} +verify_ex_errcode without_rowid3-17.1.2b SQLITE_CONSTRAINT_FOREIGNKEY +ifcapable autoreset { + do_test without_rowid3-17.1.3 { + sqlite3_step $STMT + } {SQLITE_CONSTRAINT} + verify_ex_errcode without_rowid3-17.1.3b SQLITE_CONSTRAINT_FOREIGNKEY +} else { + do_test without_rowid3-17.1.3 { + sqlite3_step $STMT + } {SQLITE_MISUSE} +} +do_test without_rowid3-17.1.4 { + sqlite3_finalize $STMT +} {SQLITE_CONSTRAINT} +verify_ex_errcode without_rowid3-17.1.4b SQLITE_CONSTRAINT_FOREIGNKEY +do_test without_rowid3-17.1.5 { + execsql { + INSERT INTO one VALUES(2, 3, 4); + INSERT INTO one VALUES(3, 4, 5); + INSERT INTO two VALUES(1, 2, 3); + INSERT INTO two VALUES(2, 3, 4); + INSERT INTO two VALUES(3, 4, 5); + } +} {1 1 1 1 1} +do_test without_rowid3-17.1.6 { + catchsql { + BEGIN; + INSERT INTO one VALUES(0, 0, 0); + UPDATE two SET e=e+1, f=f+1; + } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-17.1.7 { + execsql { SELECT * FROM one } +} {1 2 3 2 3 4 3 4 5 0 0 0} +do_test without_rowid3-17.1.8 { + execsql { SELECT * FROM two } +} {1 2 3 2 3 4 3 4 5} +do_test without_rowid3-17.1.9 { + execsql COMMIT +} {} +do_test without_rowid3-17.1.10 { + execsql { + CREATE TABLE three( + g, h, i, + FOREIGN KEY(h, i) REFERENCES one(b, c) DEFERRABLE INITIALLY DEFERRED + ); + } +} {} +do_test without_rowid3-17.1.11 { + set STMT [sqlite3_prepare_v2 db "INSERT INTO three VALUES(7, 8, 9)" -1 dummy] + sqlite3_step $STMT +} {SQLITE_ROW} +do_test without_rowid3-17.1.12 { + sqlite3_column_text $STMT 0 +} {1} +do_test without_rowid3-17.1.13 { + sqlite3_step $STMT +} {SQLITE_CONSTRAINT} +verify_ex_errcode without_rowid3-17.1.13b SQLITE_CONSTRAINT_FOREIGNKEY +do_test without_rowid3-17.1.14 { + sqlite3_finalize $STMT +} {SQLITE_CONSTRAINT} +verify_ex_errcode without_rowid3-17.1.14b SQLITE_CONSTRAINT_FOREIGNKEY + +drop_all_tables +do_test without_rowid3-17.2.1 { + execsql { + CREATE TABLE high("a'b!" PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE low( + c, + "d&6" REFERENCES high ON UPDATE CASCADE ON DELETE CASCADE + ); + } +} {} +do_test without_rowid3-17.2.2 { + execsql { + INSERT INTO high VALUES('a', 'b'); + INSERT INTO low VALUES('b', 'a'); + } + db changes +} {1} +set nTotal [db total_changes] +do_test without_rowid3-17.2.3 { + execsql { UPDATE high SET "a'b!" = 'c' } +} {1} +do_test without_rowid3-17.2.4 { + db changes +} {1} +do_test without_rowid3-17.2.5 { + expr [db total_changes] - $nTotal +} {2} +do_test without_rowid3-17.2.6 { + execsql { SELECT * FROM high ; SELECT * FROM low } +} {c b b c} +do_test without_rowid3-17.2.7 { + execsql { DELETE FROM high } +} {1} +do_test without_rowid3-17.2.8 { + db changes +} {1} +do_test without_rowid3-17.2.9 { + expr [db total_changes] - $nTotal +} {4} +do_test without_rowid3-17.2.10 { + execsql { SELECT * FROM high ; SELECT * FROM low } +} {} +execsql { PRAGMA count_changes = 0 } + +#------------------------------------------------------------------------- +# Test that the authorization callback works. +# + +ifcapable auth { + do_test without_rowid3-18.1 { + execsql { + CREATE TABLE long(a, b PRIMARY KEY, c) WITHOUT rowid; + CREATE TABLE short(d, e, f REFERENCES long); + CREATE TABLE mid(g, h, i REFERENCES long DEFERRABLE INITIALLY DEFERRED); + } + } {} + + proc auth {args} {eval lappend ::authargs $args ; return SQLITE_OK} + db auth auth + + # An insert on the parent table must read the child key of any deferred + # foreign key constraints. But not the child key of immediate constraints. + set authargs {} + do_test without_rowid3-18.2 { + execsql { INSERT INTO long VALUES(1, 2, 3) } + set authargs + } {SQLITE_INSERT long {} main {} SQLITE_READ mid i main {}} + + # An insert on the child table of an immediate constraint must read the + # parent key columns (to see if it is a violation or not). + set authargs {} + do_test without_rowid3-18.3 { + execsql { INSERT INTO short VALUES(1, 3, 2) } + set authargs + } {SQLITE_INSERT short {} main {} SQLITE_READ long b main {}} + + # As must an insert on the child table of a deferred constraint. + set authargs {} + do_test without_rowid3-18.4 { + execsql { INSERT INTO mid VALUES(1, 3, 2) } + set authargs + } {SQLITE_INSERT mid {} main {} SQLITE_READ long b main {}} + + do_test without_rowid3-18.5 { + execsql { + CREATE TABLE nought(a, b PRIMARY KEY, c) WITHOUT rowid; + CREATE TABLE cross(d, e, f, + FOREIGN KEY(e) REFERENCES nought(b) ON UPDATE CASCADE + ); + } + execsql { INSERT INTO nought VALUES(2, 1, 2) } + execsql { INSERT INTO cross VALUES(0, 1, 0) } + set authargs [list] + execsql { UPDATE nought SET b = 5 } + set authargs + } {SQLITE_UPDATE nought b main {} SQLITE_READ cross e main {} SQLITE_READ cross e main {} SQLITE_READ nought b main {} SQLITE_READ nought b main {} SQLITE_READ nought b main {} SQLITE_UPDATE cross e main {} SQLITE_READ nought b main {} SQLITE_READ cross e main {} SQLITE_READ nought b main {} SQLITE_READ nought b main {}} + + do_test without_rowid3-18.6 { + execsql {SELECT * FROM cross} + } {0 5 0} + + do_test without_rowid3-18.7 { + execsql { + CREATE TABLE one(a INT PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE two(b, c REFERENCES one); + INSERT INTO one VALUES(101, 102); + } + set authargs [list] + execsql { INSERT INTO two VALUES(100, 101); } + set authargs + } {SQLITE_INSERT two {} main {} SQLITE_READ one a main {}} + + # Return SQLITE_IGNORE to requests to read from the parent table. This + # causes inserts of non-NULL keys into the child table to fail. + # + rename auth {} + proc auth {args} { + if {[lindex $args 1] == "long"} {return SQLITE_IGNORE} + return SQLITE_OK + } + do_test without_rowid3-18.8 { + catchsql { INSERT INTO short VALUES(1, 3, 2) } + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-18.9 { + execsql { INSERT INTO short VALUES(1, 3, NULL) } + } {} + do_test without_rowid3-18.10 { + execsql { SELECT * FROM short } + } {1 3 2 1 3 {}} + do_test without_rowid3-18.11 { + catchsql { UPDATE short SET f = 2 WHERE f IS NULL } + } {1 {FOREIGN KEY constraint failed}} + + db auth {} + unset authargs +} + + +do_test without_rowid3-19.1 { + execsql { + CREATE TABLE main(id INT PRIMARY KEY) WITHOUT rowid; + CREATE TABLE sub(id INT REFERENCES main(id)); + INSERT INTO main VALUES(1); + INSERT INTO main VALUES(2); + INSERT INTO sub VALUES(2); + } +} {} +do_test without_rowid3-19.2 { + set S [sqlite3_prepare_v2 db "DELETE FROM main WHERE id = ?" -1 dummy] + sqlite3_bind_int $S 1 2 + sqlite3_step $S +} {SQLITE_CONSTRAINT} +verify_ex_errcode without_rowid3-19.2b SQLITE_CONSTRAINT_FOREIGNKEY +do_test without_rowid3-19.3 { + sqlite3_reset $S +} {SQLITE_CONSTRAINT} +verify_ex_errcode without_rowid3-19.3b SQLITE_CONSTRAINT_FOREIGNKEY +do_test without_rowid3-19.4 { + sqlite3_bind_int $S 1 1 + sqlite3_step $S +} {SQLITE_DONE} +do_test without_rowid3-19.4 { + sqlite3_finalize $S +} {SQLITE_OK} + +drop_all_tables +do_test without_rowid3-20.1 { + execsql { + CREATE TABLE pp(a PRIMARY KEY, b) WITHOUT rowid; + CREATE TABLE cc(c PRIMARY KEY, d REFERENCES pp) WITHOUT rowid; + } +} {} + +foreach {tn insert} { + 1 "INSERT" + 2 "INSERT OR IGNORE" + 3 "INSERT OR ABORT" + 4 "INSERT OR ROLLBACK" + 5 "INSERT OR REPLACE" + 6 "INSERT OR FAIL" +} { + do_test without_rowid3-20.2.$tn.1 { + catchsql "$insert INTO cc VALUES(1, 2)" + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-20.2.$tn.2 { + execsql { SELECT * FROM cc } + } {} + do_test without_rowid3-20.2.$tn.3 { + execsql { + BEGIN; + INSERT INTO pp VALUES(2, 'two'); + INSERT INTO cc VALUES(1, 2); + } + catchsql "$insert INTO cc VALUES(3, 4)" + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-20.2.$tn.4 { + execsql { COMMIT ; SELECT * FROM cc } + } {1 2} + do_test without_rowid3-20.2.$tn.5 { + execsql { DELETE FROM cc ; DELETE FROM pp } + } {} +} + +foreach {tn update} { + 1 "UPDATE" + 2 "UPDATE OR IGNORE" + 3 "UPDATE OR ABORT" + 4 "UPDATE OR ROLLBACK" + 5 "UPDATE OR REPLACE" + 6 "UPDATE OR FAIL" +} { + do_test without_rowid3-20.3.$tn.1 { + execsql { + INSERT INTO pp VALUES(2, 'two'); + INSERT INTO cc VALUES(1, 2); + } + } {} + do_test without_rowid3-20.3.$tn.2 { + catchsql "$update pp SET a = 1" + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-20.3.$tn.3 { + execsql { SELECT * FROM pp } + } {2 two} + do_test without_rowid3-20.3.$tn.4 { + catchsql "$update cc SET d = 1" + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-20.3.$tn.5 { + execsql { SELECT * FROM cc } + } {1 2} + do_test without_rowid3-20.3.$tn.6 { + execsql { + BEGIN; + INSERT INTO pp VALUES(3, 'three'); + } + catchsql "$update pp SET a = 1 WHERE a = 2" + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-20.3.$tn.7 { + execsql { COMMIT ; SELECT * FROM pp } + } {2 two 3 three} + do_test without_rowid3-20.3.$tn.8 { + execsql { + BEGIN; + INSERT INTO cc VALUES(2, 2); + } + catchsql "$update cc SET d = 1 WHERE c = 1" + } {1 {FOREIGN KEY constraint failed}} + do_test without_rowid3-20.3.$tn.9 { + execsql { COMMIT ; SELECT * FROM cc } + } {1 2 2 2} + do_test without_rowid3-20.3.$tn.10 { + execsql { DELETE FROM cc ; DELETE FROM pp } + } {} +} + +#------------------------------------------------------------------------- +# The following block of tests, those prefixed with "without_rowid3-genfkey.", +# are the same tests that were used to test the ".genfkey" command provided +# by the shell tool. So these tests show that the built-in foreign key +# implementation is more or less compatible with the triggers generated +# by genfkey. +# +drop_all_tables +do_test without_rowid3-genfkey.1.1 { + execsql { + CREATE TABLE t1(a INT PRIMARY KEY, b, c, UNIQUE(b, c)) WITHOUT rowid; + CREATE TABLE t2(e REFERENCES t1, f); + CREATE TABLE t3(g, h, i, FOREIGN KEY (h, i) REFERENCES t1(b, c)); + } +} {} +do_test without_rowid3-genfkey.1.2 { + catchsql { INSERT INTO t2 VALUES(1, 2) } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-genfkey.1.3 { + execsql { + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t2 VALUES(1, 2); + } +} {} +do_test without_rowid3-genfkey.1.4 { + execsql { INSERT INTO t2 VALUES(NULL, 3) } +} {} +do_test without_rowid3-genfkey.1.5 { + catchsql { UPDATE t2 SET e = 5 WHERE e IS NULL } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-genfkey.1.6 { + execsql { UPDATE t2 SET e = 1 WHERE e IS NULL } +} {} +do_test without_rowid3-genfkey.1.7 { + execsql { UPDATE t2 SET e = NULL WHERE f = 3 } +} {} +do_test without_rowid3-genfkey.1.8 { + catchsql { UPDATE t1 SET a = 10 } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-genfkey.1.9 { + catchsql { UPDATE t1 SET a = NULL } +} {1 {NOT NULL constraint failed: t1.a}} +do_test without_rowid3-genfkey.1.10 { + catchsql { DELETE FROM t1 } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-genfkey.1.11 { + execsql { UPDATE t2 SET e = NULL } +} {} +do_test without_rowid3-genfkey.1.12 { + execsql { + UPDATE t1 SET a = 10; + DELETE FROM t1; + DELETE FROM t2; + } +} {} +do_test without_rowid3-genfkey.1.13 { + execsql { + INSERT INTO t3 VALUES(1, NULL, NULL); + INSERT INTO t3 VALUES(1, 2, NULL); + INSERT INTO t3 VALUES(1, NULL, 3); + } +} {} +do_test without_rowid3-genfkey.1.14 { + catchsql { INSERT INTO t3 VALUES(3, 1, 4) } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-genfkey.1.15 { + execsql { + INSERT INTO t1 VALUES(1, 1, 4); + INSERT INTO t3 VALUES(3, 1, 4); + } +} {} +do_test without_rowid3-genfkey.1.16 { + catchsql { DELETE FROM t1 } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-genfkey.1.17 { + catchsql { UPDATE t1 SET b = 10} +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-genfkey.1.18 { + execsql { UPDATE t1 SET a = 10} +} {} +do_test without_rowid3-genfkey.1.19 { + catchsql { UPDATE t3 SET h = 'hello' WHERE i = 3} +} {1 {FOREIGN KEY constraint failed}} + +drop_all_tables +do_test without_rowid3-genfkey.2.1 { + execsql { + CREATE TABLE t1(a INT PRIMARY KEY, b, c, UNIQUE(b, c)) WITHOUT rowid; + CREATE TABLE t2(e REFERENCES t1 ON UPDATE CASCADE ON DELETE CASCADE, f); + CREATE TABLE t3(g, h, i, + FOREIGN KEY (h, i) + REFERENCES t1(b, c) ON UPDATE CASCADE ON DELETE CASCADE + ); + } +} {} +do_test without_rowid3-genfkey.2.2 { + execsql { + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t1 VALUES(4, 5, 6); + INSERT INTO t2 VALUES(1, 'one'); + INSERT INTO t2 VALUES(4, 'four'); + } +} {} +do_test without_rowid3-genfkey.2.3 { + execsql { + UPDATE t1 SET a = 2 WHERE a = 1; + SELECT * FROM t2; + } +} {2 one 4 four} +do_test without_rowid3-genfkey.2.4 { + execsql { + DELETE FROM t1 WHERE a = 4; + SELECT * FROM t2; + } +} {2 one} + +do_test without_rowid3-genfkey.2.5 { + execsql { + INSERT INTO t3 VALUES('hello', 2, 3); + UPDATE t1 SET c = 2; + SELECT * FROM t3; + } +} {hello 2 2} +do_test without_rowid3-genfkey.2.6 { + execsql { + DELETE FROM t1; + SELECT * FROM t3; + } +} {} + +drop_all_tables +do_test without_rowid3-genfkey.3.1 { + execsql { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(c, b)) WITHOUT rowid; + CREATE TABLE t2(e REFERENCES t1 ON UPDATE SET NULL ON DELETE SET NULL, f); + CREATE TABLE t3(g, h, i, + FOREIGN KEY (h, i) + REFERENCES t1(b, c) ON UPDATE SET NULL ON DELETE SET NULL + ); + } +} {} +do_test without_rowid3-genfkey.3.2 { + execsql { + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t1 VALUES(4, 5, 6); + INSERT INTO t2 VALUES(1, 'one'); + INSERT INTO t2 VALUES(4, 'four'); + } +} {} +do_test without_rowid3-genfkey.3.3 { + execsql { + UPDATE t1 SET a = 2 WHERE a = 1; + SELECT * FROM t2; + } +} {{} one 4 four} +do_test without_rowid3-genfkey.3.4 { + execsql { + DELETE FROM t1 WHERE a = 4; + SELECT * FROM t2; + } +} {{} one {} four} +do_test without_rowid3-genfkey.3.5 { + execsql { + INSERT INTO t3 VALUES('hello', 2, 3); + UPDATE t1 SET c = 2; + SELECT * FROM t3; + } +} {hello {} {}} +do_test without_rowid3-genfkey.3.6 { + execsql { + UPDATE t3 SET h = 2, i = 2; + DELETE FROM t1; + SELECT * FROM t3; + } +} {hello {} {}} + +#------------------------------------------------------------------------- +# Verify that ticket dd08e5a988d00decc4a543daa8dbbfab9c577ad8 has been +# fixed. +# +do_test without_rowid3-dd08e5.1.1 { + execsql { + PRAGMA foreign_keys=ON; + CREATE TABLE tdd08(a INTEGER PRIMARY KEY, b) WITHOUT rowid; + CREATE UNIQUE INDEX idd08 ON tdd08(a,b); + INSERT INTO tdd08 VALUES(200,300); + + CREATE TABLE tdd08_b(w,x,y, FOREIGN KEY(x,y) REFERENCES tdd08(a,b)); + INSERT INTO tdd08_b VALUES(100,200,300); + } +} {} +do_test without_rowid3-dd08e5.1.2 { + catchsql { + DELETE FROM tdd08; + } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-dd08e5.1.3 { + execsql { + SELECT * FROM tdd08; + } +} {200 300} +do_test without_rowid3-dd08e5.1.4 { + catchsql { + INSERT INTO tdd08_b VALUES(400,500,300); + } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-dd08e5.1.5 { + catchsql { + UPDATE tdd08_b SET x=x+1; + } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-dd08e5.1.6 { + catchsql { + UPDATE tdd08 SET a=a+1; + } +} {1 {FOREIGN KEY constraint failed}} + +#------------------------------------------------------------------------- +# Verify that ticket ce7c133ea6cc9ccdc1a60d80441f80b6180f5eba +# fixed. +# +do_test without_rowid3-ce7c13.1.1 { + execsql { + CREATE TABLE tce71(a INTEGER PRIMARY KEY, b) WITHOUT rowid; + CREATE UNIQUE INDEX ice71 ON tce71(a,b); + INSERT INTO tce71 VALUES(100,200); + CREATE TABLE tce72(w, x, y, FOREIGN KEY(x,y) REFERENCES tce71(a,b)); + INSERT INTO tce72 VALUES(300,100,200); + UPDATE tce71 set b = 200 where a = 100; + SELECT * FROM tce71, tce72; + } +} {100 200 300 100 200} +do_test without_rowid3-ce7c13.1.2 { + catchsql { + UPDATE tce71 set b = 201 where a = 100; + } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-ce7c13.1.3 { + catchsql { + UPDATE tce71 set a = 101 where a = 100; + } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-ce7c13.1.4 { + execsql { + CREATE TABLE tce73(a INTEGER PRIMARY KEY, b, UNIQUE(a,b)) WITHOUT rowid; + INSERT INTO tce73 VALUES(100,200); + CREATE TABLE tce74(w, x, y, FOREIGN KEY(x,y) REFERENCES tce73(a,b)); + INSERT INTO tce74 VALUES(300,100,200); + UPDATE tce73 set b = 200 where a = 100; + SELECT * FROM tce73, tce74; + } +} {100 200 300 100 200} +do_test without_rowid3-ce7c13.1.5 { + catchsql { + UPDATE tce73 set b = 201 where a = 100; + } +} {1 {FOREIGN KEY constraint failed}} +do_test without_rowid3-ce7c13.1.6 { + catchsql { + UPDATE tce73 set a = 101 where a = 100; + } +} {1 {FOREIGN KEY constraint failed}} + +finish_test diff --git a/test/without_rowid4.test b/test/without_rowid4.test new file mode 100644 index 0000000..d8c2d69 --- /dev/null +++ b/test/without_rowid4.test @@ -0,0 +1,764 @@ +# 2013-11-04 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Regression testing of FOR EACH ROW table triggers on WITHOUT ROWID +# tables. +# +# 1. Trigger execution order tests. +# These tests ensure that BEFORE and AFTER triggers are fired at the correct +# times relative to each other and the triggering statement. +# +# without_rowid4-1.1.*: ON UPDATE trigger execution model. +# without_rowid4-1.2.*: DELETE trigger execution model. +# without_rowid4-1.3.*: INSERT trigger execution model. +# +# 2. Trigger program execution tests. +# These tests ensure that trigger programs execute correctly (ie. that a +# trigger program can correctly execute INSERT, UPDATE, DELETE * SELECT +# statements, and combinations thereof). +# +# 3. Selective trigger execution +# This tests that conditional triggers (ie. UPDATE OF triggers and triggers +# with WHEN clauses) are fired only fired when they are supposed to be. +# +# without_rowid4-3.1: UPDATE OF triggers +# without_rowid4-3.2: WHEN clause +# +# 4. Cascaded trigger execution +# Tests that trigger-programs may cause other triggers to fire. Also that a +# trigger-program is never executed recursively. +# +# without_rowid4-4.1: Trivial cascading trigger +# without_rowid4-4.2: Trivial recursive trigger handling +# +# 5. Count changes behaviour. +# Verify that rows altered by triggers are not included in the return value +# of the "count changes" interface. +# +# 6. ON CONFLICT clause handling +# without_rowid4-6.1[a-f]: INSERT statements +# without_rowid4-6.2[a-f]: UPDATE statements +# +# 7. & 8. Triggers on views fire correctly. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +ifcapable {!trigger} { + finish_test + return +} + +# The tests in this file were written before SQLite supported recursive +# trigger invocation, and some tests depend on that to pass. So disable +# recursive triggers for this file. +catchsql { pragma recursive_triggers = off } + +# 1. +ifcapable subquery { + set ii 0 + set tbl_definitions [list \ + {CREATE TABLE tbl (a INTEGER PRIMARY KEY, b) WITHOUT rowid;} \ + {CREATE TABLE tbl (a, b PRIMARY KEY) WITHOUT rowid;} \ + {CREATE TABLE tbl (a PRIMARY KEY, b) WITHOUT rowid; + CREATE INDEX tbl_idx ON tbl(b);} \ + ] + ifcapable tempdb { + lappend tbl_definitions \ + {CREATE TEMP TABLE tbl (a PRIMARY KEY, b) WITHOUT rowid; + CREATE INDEX tbl_idx ON tbl(b);} + lappend tbl_definitions \ + {CREATE TEMP TABLE tbl (a PRIMARY KEY, b) WITHOUT rowid} + lappend tbl_definitions \ + {CREATE TEMPORARY TABLE tbl (a INTEGER PRIMARY KEY, b) WITHOUT rowid;} + } + foreach tbl_defn $tbl_definitions { + incr ii + catchsql { DROP INDEX tbl_idx; } + catchsql { + DROP TABLE rlog; + DROP TABLE clog; + DROP TABLE tbl; + DROP TABLE other_tbl; + } + + execsql $tbl_defn + + execsql { + INSERT INTO tbl VALUES(1, 2); + INSERT INTO tbl VALUES(3, 4); + + CREATE TABLE rlog (idx, old_a, old_b, db_sum_a, db_sum_b, new_a, new_b); + CREATE TABLE clog (idx, old_a, old_b, db_sum_a, db_sum_b, new_a, new_b); + + CREATE TRIGGER before_update_row BEFORE UPDATE ON tbl FOR EACH ROW + BEGIN + INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), + old.a, old.b, + (SELECT coalesce(sum(a),0) FROM tbl), + (SELECT coalesce(sum(b),0) FROM tbl), + new.a, new.b); + END; + + CREATE TRIGGER after_update_row AFTER UPDATE ON tbl FOR EACH ROW + BEGIN + INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), + old.a, old.b, + (SELECT coalesce(sum(a),0) FROM tbl), + (SELECT coalesce(sum(b),0) FROM tbl), + new.a, new.b); + END; + + CREATE TRIGGER conditional_update_row AFTER UPDATE ON tbl FOR EACH ROW + WHEN old.a = 1 + BEGIN + INSERT INTO clog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM clog), + old.a, old.b, + (SELECT coalesce(sum(a),0) FROM tbl), + (SELECT coalesce(sum(b),0) FROM tbl), + new.a, new.b); + END; + } + + do_test without_rowid4-1.$ii.1 { + set r {} + foreach v [execsql { + UPDATE tbl SET a = a * 10, b = b * 10; + SELECT * FROM rlog ORDER BY idx; + SELECT * FROM clog ORDER BY idx; + }] { + lappend r [expr {int($v)}] + } + set r + } [list 1 1 2 4 6 10 20 \ + 2 1 2 13 24 10 20 \ + 3 3 4 13 24 30 40 \ + 4 3 4 40 60 30 40 \ + 1 1 2 13 24 10 20 ] + + execsql { + DELETE FROM rlog; + DELETE FROM tbl; + INSERT INTO tbl VALUES (100, 100); + INSERT INTO tbl VALUES (300, 200); + CREATE TRIGGER delete_before_row BEFORE DELETE ON tbl FOR EACH ROW + BEGIN + INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), + old.a, old.b, + (SELECT coalesce(sum(a),0) FROM tbl), + (SELECT coalesce(sum(b),0) FROM tbl), + 0, 0); + END; + + CREATE TRIGGER delete_after_row AFTER DELETE ON tbl FOR EACH ROW + BEGIN + INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), + old.a, old.b, + (SELECT coalesce(sum(a),0) FROM tbl), + (SELECT coalesce(sum(b),0) FROM tbl), + 0, 0); + END; + } + do_test without_rowid4-1.$ii.2 { + set r {} + foreach v [execsql { + DELETE FROM tbl; + SELECT * FROM rlog; + }] { + lappend r [expr {int($v)}] + } + set r + } [list 1 100 100 400 300 0 0 \ + 2 100 100 300 200 0 0 \ + 3 300 200 300 200 0 0 \ + 4 300 200 0 0 0 0 ] + + execsql { + DELETE FROM rlog; + CREATE TRIGGER insert_before_row BEFORE INSERT ON tbl FOR EACH ROW + BEGIN + INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), + 0, 0, + (SELECT coalesce(sum(a),0) FROM tbl), + (SELECT coalesce(sum(b),0) FROM tbl), + new.a, new.b); + END; + + CREATE TRIGGER insert_after_row AFTER INSERT ON tbl FOR EACH ROW + BEGIN + INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), + 0, 0, + (SELECT coalesce(sum(a),0) FROM tbl), + (SELECT coalesce(sum(b),0) FROM tbl), + new.a, new.b); + END; + } + do_test without_rowid4-1.$ii.3 { + execsql { + + CREATE TABLE other_tbl(a, b); + INSERT INTO other_tbl VALUES(1, 2); + INSERT INTO other_tbl VALUES(3, 4); + -- INSERT INTO tbl SELECT * FROM other_tbl; + INSERT INTO tbl VALUES(5, 6); + DROP TABLE other_tbl; + + SELECT * FROM rlog; + } + } [list 1 0 0 0 0 5 6 \ + 2 0 0 5 6 5 6 ] + + integrity_check without_rowid4-1.$ii.4 + } + catchsql { + DROP TABLE rlog; + DROP TABLE clog; + DROP TABLE tbl; + DROP TABLE other_tbl; + } +} + +# 2. +set ii 0 +foreach tr_program { + {UPDATE tbl SET b = old.b;} + {INSERT INTO log VALUES(new.c, 2, 3);} + {DELETE FROM log WHERE a = 1;} + {INSERT INTO tbl VALUES(500, new.b * 10, 700); + UPDATE tbl SET c = old.c; + DELETE FROM log;} + {INSERT INTO log select * from tbl;} +} { + foreach test_varset [ list \ + { + set statement {UPDATE tbl SET c = 10 WHERE a = 1;} + set prep {INSERT INTO tbl VALUES(1, 2, 3);} + set newC 10 + set newB 2 + set newA 1 + set oldA 1 + set oldB 2 + set oldC 3 + } \ + { + set statement {DELETE FROM tbl WHERE a = 1;} + set prep {INSERT INTO tbl VALUES(1, 2, 3);} + set oldA 1 + set oldB 2 + set oldC 3 + } \ + { + set statement {INSERT INTO tbl VALUES(1, 2, 3);} + set newA 1 + set newB 2 + set newC 3 + } + ] \ + { + set statement {} + set prep {} + set newA {''} + set newB {''} + set newC {''} + set oldA {''} + set oldB {''} + set oldC {''} + + incr ii + + eval $test_varset + + set statement_type [string range $statement 0 5] + set tr_program_fixed $tr_program + if {$statement_type == "DELETE"} { + regsub -all new\.a $tr_program_fixed {''} tr_program_fixed + regsub -all new\.b $tr_program_fixed {''} tr_program_fixed + regsub -all new\.c $tr_program_fixed {''} tr_program_fixed + } + if {$statement_type == "INSERT"} { + regsub -all old\.a $tr_program_fixed {''} tr_program_fixed + regsub -all old\.b $tr_program_fixed {''} tr_program_fixed + regsub -all old\.c $tr_program_fixed {''} tr_program_fixed + } + + + set tr_program_cooked $tr_program + regsub -all new\.a $tr_program_cooked $newA tr_program_cooked + regsub -all new\.b $tr_program_cooked $newB tr_program_cooked + regsub -all new\.c $tr_program_cooked $newC tr_program_cooked + regsub -all old\.a $tr_program_cooked $oldA tr_program_cooked + regsub -all old\.b $tr_program_cooked $oldB tr_program_cooked + regsub -all old\.c $tr_program_cooked $oldC tr_program_cooked + + catchsql { + DROP TABLE tbl; + DROP TABLE log; + } + + execsql { + CREATE TABLE tbl(a PRIMARY KEY, b, c) WITHOUT rowid; + CREATE TABLE log(a, b, c); + } + + set query {SELECT * FROM tbl; SELECT * FROM log;} + set prep "$prep; INSERT INTO log VALUES(1, 2, 3);\ + INSERT INTO log VALUES(10, 20, 30);" + +# Check execution of BEFORE programs: + + set before_data [ execsql "$prep $tr_program_cooked $statement $query" ] + + execsql "DELETE FROM tbl; DELETE FROM log; $prep"; + execsql "CREATE TRIGGER the_trigger BEFORE [string range $statement 0 6]\ + ON tbl BEGIN $tr_program_fixed END;" + + do_test without_rowid4-2.$ii-before "execsql {$statement $query}" $before_data + + execsql "DROP TRIGGER the_trigger;" + execsql "DELETE FROM tbl; DELETE FROM log;" + +# Check execution of AFTER programs + set after_data [ execsql "$prep $statement $tr_program_cooked $query" ] + + execsql "DELETE FROM tbl; DELETE FROM log; $prep"; + execsql "CREATE TRIGGER the_trigger AFTER [string range $statement 0 6]\ + ON tbl BEGIN $tr_program_fixed END;" + + do_test without_rowid4-2.$ii-after "execsql {$statement $query}" $after_data + execsql "DROP TRIGGER the_trigger;" + + integrity_check without_rowid4-2.$ii-integrity + } +} +catchsql { + DROP TABLE tbl; + DROP TABLE log; +} + +# 3. + +# without_rowid4-3.1: UPDATE OF triggers +execsql { + CREATE TABLE tbl (a, b, c, d, PRIMARY KEY(a,b,c,d)) WITHOUT rowid; + CREATE TABLE log (a); + INSERT INTO log VALUES (0); + INSERT INTO tbl VALUES (0, 0, 0, 0); + INSERT INTO tbl VALUES (1, 0, 0, 0); + CREATE TRIGGER tbl_after_update_cd BEFORE UPDATE OF c, d ON tbl + BEGIN + UPDATE log SET a = a + 1; + END; +} +do_test without_rowid4-3.1 { + execsql { + UPDATE tbl SET b = 1, c = 10; -- 2 + UPDATE tbl SET b = 10; -- 0 + UPDATE tbl SET d = 4 WHERE a = 0; --1 + UPDATE tbl SET a = 4, b = 10; --0 + SELECT * FROM log; + } +} {3} +execsql { + DROP TABLE tbl; + DROP TABLE log; +} + +# without_rowid4-3.2: WHEN clause +set when_triggers [list {t1 BEFORE INSERT ON tbl WHEN new.a > 20}] +ifcapable subquery { + lappend when_triggers \ + {t2 BEFORE INSERT ON tbl WHEN (SELECT count(*) FROM tbl) = 0} +} + +execsql { + CREATE TABLE tbl (a, b, c, d); + CREATE TABLE log (a); + INSERT INTO log VALUES (0); +} + +foreach trig $when_triggers { + execsql "CREATE TRIGGER $trig BEGIN UPDATE log set a = a + 1; END;" +} + +ifcapable subquery { + set t232 {1 0 1} +} else { + set t232 {0 0 1} +} +do_test without_rowid4-3.2 { + execsql { + + INSERT INTO tbl VALUES(0, 0, 0, 0); -- 1 (ifcapable subquery) + SELECT * FROM log; + UPDATE log SET a = 0; + + INSERT INTO tbl VALUES(0, 0, 0, 0); -- 0 + SELECT * FROM log; + UPDATE log SET a = 0; + + INSERT INTO tbl VALUES(200, 0, 0, 0); -- 1 + SELECT * FROM log; + UPDATE log SET a = 0; + } +} $t232 +execsql { + DROP TABLE tbl; + DROP TABLE log; +} +integrity_check without_rowid4-3.3 + +# Simple cascaded trigger +execsql { + CREATE TABLE tblA(a, b, PRIMARY KEY(a,b)) WITHOUT rowid; + CREATE TABLE tblB(a, b, PRIMARY KEY(a,b)) WITHOUT rowid; + CREATE TABLE tblC(a, b, PRIMARY KEY(a,b)) WITHOUT rowid; + + CREATE TRIGGER tr1 BEFORE INSERT ON tblA BEGIN + INSERT INTO tblB values(new.a, new.b); + END; + + CREATE TRIGGER tr2 BEFORE INSERT ON tblB BEGIN + INSERT INTO tblC values(new.a, new.b); + END; +} +do_test without_rowid4-4.1 { + execsql { + INSERT INTO tblA values(1, 2); + SELECT * FROM tblA; + SELECT * FROM tblB; + SELECT * FROM tblC; + } +} {1 2 1 2 1 2} +execsql { + DROP TABLE tblA; + DROP TABLE tblB; + DROP TABLE tblC; +} + +# Simple recursive trigger +execsql { + CREATE TABLE tbl(a, b, c, PRIMARY KEY(c,a,b)) WITHOUT rowid; + CREATE TRIGGER tbl_trig BEFORE INSERT ON tbl + BEGIN + INSERT INTO tbl VALUES (new.a, new.b, new.c+1); + END; +} +do_test without_rowid4-4.2 { + execsql { + INSERT INTO tbl VALUES (1, 2, 3); + select * from tbl; + } +} {1 2 3 1 2 4} +execsql { + DROP TABLE tbl; +} + +# 5. +execsql { + CREATE TABLE tbl(a, b, c, PRIMARY KEY(c,a,b)) WITHOUT rowid; + CREATE TRIGGER tbl_trig BEFORE INSERT ON tbl + BEGIN + INSERT INTO tbl VALUES (1, 2, 3); + INSERT INTO tbl VALUES (2, 2, 3); + UPDATE tbl set b = 10 WHERE a = 1; + DELETE FROM tbl WHERE a = 1; + DELETE FROM tbl; + END; +} +do_test without_rowid4-5 { + execsql { + INSERT INTO tbl VALUES(100, 200, 300); + } + db changes +} {1} +execsql { + DROP TABLE tbl; +} + +ifcapable conflict { + # Handling of ON CONFLICT by INSERT statements inside triggers + execsql { + CREATE TABLE tbl (a PRIMARY KEY, b, c) WITHOUT rowid; + CREATE TRIGGER ai_tbl AFTER INSERT ON tbl BEGIN + INSERT OR IGNORE INTO tbl values (new.a, 0, 0); + END; + } + do_test without_rowid4-6.1a { + execsql { + BEGIN; + INSERT INTO tbl values (1, 2, 3); + SELECT * from tbl; + } + } {1 2 3} + do_test without_rowid4-6.1b { + catchsql { + INSERT OR ABORT INTO tbl values (2, 2, 3); + } + } {1 {UNIQUE constraint failed: tbl.a}} + do_test without_rowid4-6.1c { + execsql { + SELECT * from tbl; + } + } {1 2 3} + do_test without_rowid4-6.1d { + catchsql { + INSERT OR FAIL INTO tbl values (2, 2, 3); + } + } {1 {UNIQUE constraint failed: tbl.a}} + do_test without_rowid4-6.1e { + execsql { + SELECT * from tbl; + } + } {1 2 3 2 2 3} + do_test without_rowid4-6.1f { + execsql { + INSERT OR REPLACE INTO tbl values (2, 2, 3); + SELECT * from tbl; + } + } {1 2 3 2 0 0} + do_test without_rowid4-6.1g { + catchsql { + INSERT OR ROLLBACK INTO tbl values (3, 2, 3); + } + } {1 {UNIQUE constraint failed: tbl.a}} + do_test without_rowid4-6.1h { + execsql { + SELECT * from tbl; + } + } {} + execsql {DELETE FROM tbl} + + + # Handling of ON CONFLICT by UPDATE statements inside triggers + execsql { + INSERT INTO tbl values (4, 2, 3); + INSERT INTO tbl values (6, 3, 4); + CREATE TRIGGER au_tbl AFTER UPDATE ON tbl BEGIN + UPDATE OR IGNORE tbl SET a = new.a, c = 10; + END; + } + do_test without_rowid4-6.2a { + execsql { + BEGIN; + UPDATE tbl SET a = 1 WHERE a = 4; + SELECT * from tbl; + } + } {1 2 10 6 3 4} + do_test without_rowid4-6.2b { + catchsql { + UPDATE OR ABORT tbl SET a = 4 WHERE a = 1; + } + } {1 {UNIQUE constraint failed: tbl.a}} + do_test without_rowid4-6.2c { + execsql { + SELECT * from tbl; + } + } {1 2 10 6 3 4} + do_test without_rowid4-6.2d { + catchsql { + UPDATE OR FAIL tbl SET a = 4 WHERE a = 1; + } + } {1 {UNIQUE constraint failed: tbl.a}} + do_test without_rowid4-6.2e { + execsql { + SELECT * from tbl; + } + } {4 2 10 6 3 4} + do_test without_rowid4-6.2f.1 { + execsql { + UPDATE OR REPLACE tbl SET a = 1 WHERE a = 4; + SELECT * from tbl; + } + } {1 3 10} + do_test without_rowid4-6.2f.2 { + execsql { + INSERT INTO tbl VALUES (2, 3, 4); + SELECT * FROM tbl; + } + } {1 3 10 2 3 4} + do_test without_rowid4-6.2g { + catchsql { + UPDATE OR ROLLBACK tbl SET a = 4 WHERE a = 1; + } + } {1 {UNIQUE constraint failed: tbl.a}} + do_test without_rowid4-6.2h { + execsql { + SELECT * from tbl; + } + } {4 2 3 6 3 4} + execsql { + DROP TABLE tbl; + } +} ; # ifcapable conflict + +# 7. Triggers on views +ifcapable view { + +do_test without_rowid4-7.1 { + execsql { + CREATE TABLE ab(a, b, PRIMARY KEY(a,b)) WITHOUT rowid; + CREATE TABLE cd(c, d, PRIMARY KEY(c,d)) WITHOUT rowid; + INSERT INTO ab VALUES (1, 2); + INSERT INTO ab VALUES (0, 0); + INSERT INTO cd VALUES (3, 4); + + CREATE TABLE tlog(ii INTEGER PRIMARY KEY, + olda, oldb, oldc, oldd, newa, newb, newc, newd); + + CREATE VIEW abcd AS SELECT a, b, c, d FROM ab, cd; + + CREATE TRIGGER before_update INSTEAD OF UPDATE ON abcd BEGIN + INSERT INTO tlog VALUES(NULL, + old.a, old.b, old.c, old.d, new.a, new.b, new.c, new.d); + END; + CREATE TRIGGER after_update INSTEAD OF UPDATE ON abcd BEGIN + INSERT INTO tlog VALUES(NULL, + old.a, old.b, old.c, old.d, new.a, new.b, new.c, new.d); + END; + + CREATE TRIGGER before_delete INSTEAD OF DELETE ON abcd BEGIN + INSERT INTO tlog VALUES(NULL, + old.a, old.b, old.c, old.d, 0, 0, 0, 0); + END; + CREATE TRIGGER after_delete INSTEAD OF DELETE ON abcd BEGIN + INSERT INTO tlog VALUES(NULL, + old.a, old.b, old.c, old.d, 0, 0, 0, 0); + END; + + CREATE TRIGGER before_insert INSTEAD OF INSERT ON abcd BEGIN + INSERT INTO tlog VALUES(NULL, + 0, 0, 0, 0, new.a, new.b, new.c, new.d); + END; + CREATE TRIGGER after_insert INSTEAD OF INSERT ON abcd BEGIN + INSERT INTO tlog VALUES(NULL, + 0, 0, 0, 0, new.a, new.b, new.c, new.d); + END; + } +} {}; + +do_test without_rowid4-7.2 { + execsql { + UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1; + DELETE FROM abcd WHERE a = 1; + INSERT INTO abcd VALUES(10, 20, 30, 40); + SELECT * FROM tlog; + } +} [ list 1 1 2 3 4 100 25 3 4 \ + 2 1 2 3 4 100 25 3 4 \ + 3 1 2 3 4 0 0 0 0 \ + 4 1 2 3 4 0 0 0 0 \ + 5 0 0 0 0 10 20 30 40 \ + 6 0 0 0 0 10 20 30 40 ] + +do_test without_rowid4-7.3 { + execsql { + DELETE FROM tlog; + INSERT INTO abcd VALUES(10, 20, 30, 40); + UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1; + DELETE FROM abcd WHERE a = 1; + SELECT * FROM tlog; + } +} [ list \ + 1 0 0 0 0 10 20 30 40 \ + 2 0 0 0 0 10 20 30 40 \ + 3 1 2 3 4 100 25 3 4 \ + 4 1 2 3 4 100 25 3 4 \ + 5 1 2 3 4 0 0 0 0 \ + 6 1 2 3 4 0 0 0 0 \ +] +do_test without_rowid4-7.4 { + execsql { + DELETE FROM tlog; + DELETE FROM abcd WHERE a = 1; + INSERT INTO abcd VALUES(10, 20, 30, 40); + UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1; + SELECT * FROM tlog; + } +} [ list \ + 1 1 2 3 4 0 0 0 0 \ + 2 1 2 3 4 0 0 0 0 \ + 3 0 0 0 0 10 20 30 40 \ + 4 0 0 0 0 10 20 30 40 \ + 5 1 2 3 4 100 25 3 4 \ + 6 1 2 3 4 100 25 3 4 \ +] + +do_test without_rowid4-8.1 { + execsql { + CREATE TABLE t1(a,b,c, PRIMARY KEY(a,b,c)) WITHOUT rowid; + INSERT INTO t1 VALUES(1,2,3); + CREATE VIEW v1 AS + SELECT a+b AS x, b+c AS y, a+c AS z FROM t1; + SELECT * FROM v1; + } +} {3 5 4} +do_test without_rowid4-8.2 { + execsql { + CREATE TABLE v1log(a,b,c,d,e,f); + CREATE TRIGGER r1 INSTEAD OF DELETE ON v1 BEGIN + INSERT INTO v1log VALUES(OLD.x,NULL,OLD.y,NULL,OLD.z,NULL); + END; + DELETE FROM v1 WHERE x=1; + SELECT * FROM v1log; + } +} {} +do_test without_rowid4-8.3 { + execsql { + DELETE FROM v1 WHERE x=3; + SELECT * FROM v1log; + } +} {3 {} 5 {} 4 {}} +do_test without_rowid4-8.4 { + execsql { + INSERT INTO t1 VALUES(4,5,6); + DELETE FROM v1log; + DELETE FROM v1 WHERE y=11; + SELECT * FROM v1log; + } +} {9 {} 11 {} 10 {}} +do_test without_rowid4-8.5 { + execsql { + CREATE TRIGGER r2 INSTEAD OF INSERT ON v1 BEGIN + INSERT INTO v1log VALUES(NULL,NEW.x,NULL,NEW.y,NULL,NEW.z); + END; + DELETE FROM v1log; + INSERT INTO v1 VALUES(1,2,3); + SELECT * FROM v1log; + } +} {{} 1 {} 2 {} 3} +do_test without_rowid4-8.6 { + execsql { + CREATE TRIGGER r3 INSTEAD OF UPDATE ON v1 BEGIN + INSERT INTO v1log VALUES(OLD.x,NEW.x,OLD.y,NEW.y,OLD.z,NEW.z); + END; + DELETE FROM v1log; + UPDATE v1 SET x=x+100, y=y+200, z=z+300; + SELECT * FROM v1log; + } +} {3 103 5 205 4 304 9 109 11 211 10 310} + +# At one point the following was causing a segfault. +do_test without_rowid4-9.1 { + execsql { + CREATE TABLE t3(a TEXT, b TEXT); + CREATE VIEW v3 AS SELECT t3.a FROM t3; + CREATE TRIGGER trig1 INSTEAD OF DELETE ON v3 BEGIN + SELECT 1; + END; + DELETE FROM v3 WHERE a = 1; + } +} {} + +} ;# ifcapable view + +integrity_check without_rowid4-9.9 + +finish_test diff --git a/test/without_rowid5.test b/test/without_rowid5.test new file mode 100644 index 0000000..45e047b --- /dev/null +++ b/test/without_rowid5.test @@ -0,0 +1,201 @@ +# 2013-11-26 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Requirements testing for WITHOUT ROWID tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + + +# EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a +# special column, usually called the "rowid", that uniquely identifies +# that row within the table. +# +# EVIDENCE-OF: R-32341-39358 However if the phrase "WITHOUT ROWID" is +# added to the end of a CREATE TABLE statement, then the special "rowid" +# column is omitted. +# +do_execsql_test without_rowid5-1.1 { + CREATE TABLE t1(a PRIMARY KEY,b,c); + CREATE TABLE t1w(a PRIMARY KEY,b,c) WITHOUT ROWID; + INSERT INTO t1 VALUES(1565,681,1148),(1429,1190,1619),(425,358,1306); + INSERT INTO t1w SELECT a,b,c FROM t1; + SELECT rowid, _rowid_, oid FROM t1 ORDER BY a DESC; +} {1 1 1 2 2 2 3 3 3} +do_catchsql_test without_rowid5-1.2 { + SELECT rowid FROM t1w; +} {1 {no such column: rowid}} +do_catchsql_test without_rowid5-1.3 { + SELECT _rowid_ FROM t1w; +} {1 {no such column: _rowid_}} +do_catchsql_test without_rowid5-1.4 { + SELECT oid FROM t1w; +} {1 {no such column: oid}} + +# EVIDENCE-OF: R-00217-01605 To create a WITHOUT ROWID table, simply add +# the keywords "WITHOUT ROWID" to the end of the CREATE TABLE statement. +# For example: CREATE TABLE IF NOT EXISTS wordcount( word TEXT PRIMARY +# KEY, cnt INTEGER ) WITHOUT ROWID; +# +do_execsql_test without_rowid5-2.1 { + CREATE TABLE IF NOT EXISTS wordcount( + word TEXT PRIMARY KEY, + cnt INTEGER + ) WITHOUT ROWID; + INSERT INTO wordcount VALUES('one',1); +} {} +do_catchsql_test without_rowid5-2.2 { + SELECT rowid FROM wordcount; +} {1 {no such column: rowid}} + +# EVIDENCE-OF: R-24770-17719 As with all SQL syntax, the case of the +# keywords does not matter. One can write "WITHOUT rowid" or "without +# rowid" or "WiThOuT rOwId" and it will mean the same thing. +# +do_execsql_test without_rowid5-2.3 { + CREATE TABLE IF NOT EXISTS wordcount_b( + word TEXT PRIMARY KEY, + cnt INTEGER + ) WITHOUT rowid; + INSERT INTO wordcount_b VALUES('one',1); +} {} +do_catchsql_test without_rowid5-2.4 { + SELECT rowid FROM wordcount_b; +} {1 {no such column: rowid}} +do_execsql_test without_rowid5-2.5 { + CREATE TABLE IF NOT EXISTS wordcount_c( + word TEXT PRIMARY KEY, + cnt INTEGER + ) without rowid; + INSERT INTO wordcount_c VALUES('one',1); +} {} +do_catchsql_test without_rowid5-2.6 { + SELECT rowid FROM wordcount_c; +} {1 {no such column: rowid}} +do_execsql_test without_rowid5-2.7 { + CREATE TABLE IF NOT EXISTS wordcount_d( + word TEXT PRIMARY KEY, + cnt INTEGER + ) WITHOUT rowid; + INSERT INTO wordcount_d VALUES('one',1); +} {} +do_catchsql_test without_rowid5-2.8 { + SELECT rowid FROM wordcount_d; +} {1 {no such column: rowid}} + +# EVIDENCE-OF: R-01418-51310 However, only "rowid" works as the keyword +# in the CREATE TABLE statement. +# +do_catchsql_test without_rowid5-3.1 { + CREATE TABLE IF NOT EXISTS error1( + word TEXT PRIMARY KEY, + cnt INTEGER + ) WITHOUT _rowid_; +} {1 {unknown table option: _rowid_}} +do_catchsql_test without_rowid5-3.2 { + CREATE TABLE IF NOT EXISTS error2( + word TEXT PRIMARY KEY, + cnt INTEGER + ) WITHOUT oid; +} {1 {unknown table option: oid}} + +# EVIDENCE-OF: R-58033-17334 An error is raised if a CREATE TABLE +# statement with the WITHOUT ROWID clause lacks a PRIMARY KEY. +# +# EVIDENCE-OF: R-63443-09418 Every WITHOUT ROWID table must have a +# PRIMARY KEY. +# +# EVIDENCE-OF: R-27966-31616 An attempt to create a WITHOUT ROWID table +# without a PRIMARY KEY results in an error. +# +do_catchsql_test without_rowid5-4.1 { + CREATE TABLE IF NOT EXISTS error3( + word TEXT UNIQUE, + cnt INTEGER + ) WITHOUT ROWID; +} {1 {PRIMARY KEY missing on table error3}} + +# EVIDENCE-OF: R-48230-36247 The special behaviors associated "INTEGER +# PRIMARY KEY" do not apply on WITHOUT ROWID tables. +# +do_execsql_test without_rowid5-5.1 { + CREATE TABLE ipk(key INTEGER PRIMARY KEY, val TEXT) WITHOUT ROWID; + INSERT INTO ipk VALUES('rival','bonus'); -- ok to insert non-integer key + SELECT * FROM ipk; +} {rival bonus} +do_catchsql_test without_rowid5-5.2 { + INSERT INTO ipk VALUES(NULL,'sample'); -- no automatic generation of keys +} {1 {NOT NULL constraint failed: ipk.key}} + +# EVIDENCE-OF: R-33142-02092 AUTOINCREMENT does not work on WITHOUT +# ROWID tables. +# +# EVIDENCE-OF: R-53084-07740 An error is raised if the "AUTOINCREMENT" +# keyword is used in the CREATE TABLE statement for a WITHOUT ROWID +# table. +# +do_catchsql_test without_rowid5-5.3 { + CREATE TABLE ipk2(key INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT)WITHOUT ROWID; +} {1 {AUTOINCREMENT not allowed on WITHOUT ROWID tables}} + +# EVIDENCE-OF: R-27831-00579 NOT NULL is enforced on every column of the +# PRIMARY KEY in a WITHOUT ROWID table. +# +# EVIDENCE-OF: R-29781-51289 So, ordinary rowid tables in SQLite violate +# the SQL standard and allow NULL values in PRIMARY KEY fields. +# +# EVIDENCE-OF: R-27472-62612 But WITHOUT ROWID tables do follow the +# standard and will throw an error on any attempt to insert a NULL into +# a PRIMARY KEY column. +# +do_execsql_test without_rowid5-5.4 { + CREATE TABLE nn(a, b, c, d, e, PRIMARY KEY(c,a,e)); + CREATE TABLE nnw(a, b, c, d, e, PRIMARY KEY(c,a,e)) WITHOUT ROWID; + INSERT INTO nn VALUES(1,2,3,4,5); + INSERT INTO nnw VALUES(1,2,3,4,5); +} {} +do_execsql_test without_rowid5-5.5 { + INSERT INTO nn VALUES(NULL, 3,4,5,6); + INSERT INTO nn VALUES(3,4,NULL,7,8); + INSERT INTO nn VALUES(4,5,6,7,NULL); + SELECT count(*) FROM nn; +} {4} +do_catchsql_test without_rowid5-5.6 { + INSERT INTO nnw VALUES(NULL, 3,4,5,6); +} {1 {NOT NULL constraint failed: nnw.a}} +do_catchsql_test without_rowid5-5.7 { + INSERT INTO nnw VALUES(3,4,NULL,7,8) +} {1 {NOT NULL constraint failed: nnw.c}} +do_catchsql_test without_rowid5-5.8 { + INSERT INTO nnw VALUES(4,5,6,7,NULL) +} {1 {NOT NULL constraint failed: nnw.e}} +do_execsql_test without_rowid5-5.9 { + SELECT count(*) FROM nnw; +} {1} + +# EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not +# work for WITHOUT ROWID tables. +# +# EVIDENCE-OF: R-25760-33257 The sqlite3_blob_open() interface will fail +# for a WITHOUT ROWID table. +# +do_execsql_test without_rowid5-6.1 { + CREATE TABLE b1(a INTEGER PRIMARY KEY, b BLOB) WITHOUT ROWID; + INSERT INTO b1 VALUES(1,x'0102030405060708090a0b0c0d0e0f'); +} {} +do_test without_rowid5-6.2 { + set rc [catch {db incrblob b1 b 1} msg] + lappend rc $msg +} {1 {cannot open table without rowid: b1}} + + +finish_test diff --git a/test/wordcount.c b/test/wordcount.c new file mode 100644 index 0000000..cf63e98 --- /dev/null +++ b/test/wordcount.c @@ -0,0 +1,545 @@ +/* +** This C program extracts all "words" from an input document and adds them +** to an SQLite database. A "word" is any contiguous sequence of alphabetic +** characters. All digits, punctuation, and whitespace characters are +** word separators. The database stores a single entry for each distinct +** word together with a count of the number of occurrences of that word. +** A fresh database is created automatically on each run. +** +** wordcount DATABASE INPUTFILE +** +** The INPUTFILE name can be omitted, in which case input it taken from +** standard input. +** +** Option: +** +** --without-rowid Use a WITHOUT ROWID table to store the words. +** --insert Use INSERT mode (the default) +** --replace Use REPLACE mode +** --select Use SELECT mode +** --update Use UPDATE mode +** --delete Use DELETE mode +** --query Use QUERY mode +** --nocase Add the NOCASE collating sequence to the words. +** --trace Enable sqlite3_trace() output. +** --summary Show summary information on the collected data. +** --stats Show sqlite3_status() results at the end. +** --pagesize NNN Use a page size of NNN +** --cachesize NNN Use a cache size of NNN +** --commit NNN Commit after every NNN operations +** --nosync Use PRAGMA synchronous=OFF +** --journal MMMM Use PRAGMA journal_mode=MMMM +** --timer Time the operation of this program +** +** Modes: +** +** Insert mode means: +** (1) INSERT OR IGNORE INTO wordcount VALUES($new,1) +** (2) UPDATE wordcount SET cnt=cnt+1 WHERE word=$new -- if (1) is a noop +** +** Update mode means: +** (1) INSERT OR IGNORE INTO wordcount VALUES($new,0) +** (2) UPDATE wordcount SET cnt=cnt+1 WHERE word=$new +** +** Replace mode means: +** (1) REPLACE INTO wordcount +** VALUES($new,ifnull((SELECT cnt FROM wordcount WHERE word=$new),0)+1); +** +** Select mode means: +** (1) SELECT 1 FROM wordcount WHERE word=$new +** (2) INSERT INTO wordcount VALUES($new,1) -- if (1) returns nothing +** (3) UPDATE wordcount SET cnt=cnt+1 WHERE word=$new --if (1) return TRUE +** +** Delete mode means: +** (1) DELETE FROM wordcount WHERE word=$new +** +** Query mode means: +** (1) SELECT cnt FROM wordcount WHERE word=$new +** +** Note that delete mode and query mode are only useful for preexisting +** databases. The wordcount table is created using IF NOT EXISTS so this +** utility can be run multiple times on the same database file. The +** --without-rowid, --nocase, and --pagesize parameters are only effective +** when creating a new database and are harmless no-ops on preexisting +** databases. +** +****************************************************************************** +** +** Compile as follows: +** +** gcc -I. wordcount.c sqlite3.c -ldl -lpthreads +** +** Or: +** +** gcc -I. -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ +** wordcount.c sqlite3.c +*/ +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdarg.h> +#include "sqlite3.h" + +/* Return the current wall-clock time */ +static sqlite3_int64 realTime(void){ + static sqlite3_vfs *clockVfs = 0; + sqlite3_int64 t; + if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); + if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){ + clockVfs->xCurrentTimeInt64(clockVfs, &t); + }else{ + double r; + clockVfs->xCurrentTime(clockVfs, &r); + t = (sqlite3_int64)(r*86400000.0); + } + return t; +} + +/* Print an error message and exit */ +static void fatal_error(const char *zMsg, ...){ + va_list ap; + va_start(ap, zMsg); + vfprintf(stderr, zMsg, ap); + va_end(ap); + exit(1); +} + +/* The sqlite3_trace() callback function */ +static void traceCallback(void *NotUsed, const char *zSql){ + printf("%s;\n", zSql); +} + +/* An sqlite3_exec() callback that prints results on standard output, +** each column separated by a single space. */ +static int printResult(void *NotUsed, int nArg, char **azArg, char **azNm){ + int i; + printf("--"); + for(i=0; i<nArg; i++){ + printf(" %s", azArg[i] ? azArg[i] : "(null)"); + } + printf("\n"); + return 0; +} + + +/* +** Add one character to a hash +*/ +static void addCharToHash(unsigned int *a, unsigned char x){ + if( a[0]<4 ){ + a[1] = (a[1]<<8) | x; + a[0]++; + }else{ + a[2] = (a[2]<<8) | x; + a[0]++; + if( a[0]==8 ){ + a[3] += a[1] + a[4]; + a[4] += a[2] + a[3]; + a[0] = a[1] = a[2] = 0; + } + } +} + +/* +** Compute the final hash value. +*/ +static void finalHash(unsigned int *a, char *z){ + a[3] += a[1] + a[4] + a[0]; + a[4] += a[2] + a[3]; + sqlite3_snprintf(17, z, "%08x%08x", a[3], a[4]); +} + + +/* +** Implementation of a checksum() aggregate SQL function +*/ +static void checksumStep( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zVal; + int nVal, i, j; + unsigned int *a; + a = (unsigned*)sqlite3_aggregate_context(context, sizeof(unsigned int)*5); + + if( a ){ + for(i=0; i<argc; i++){ + nVal = sqlite3_value_bytes(argv[i]); + zVal = (const unsigned char*)sqlite3_value_text(argv[i]); + if( zVal ) for(j=0; j<nVal; j++) addCharToHash(a, zVal[j]); + addCharToHash(a, '|'); + } + addCharToHash(a, '\n'); + } +} +static void checksumFinalize(sqlite3_context *context){ + unsigned int *a; + char zResult[24]; + a = sqlite3_aggregate_context(context, 0); + if( a ){ + finalHash(a, zResult); + sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); + } +} + + +/* Define operating modes */ +#define MODE_INSERT 0 +#define MODE_REPLACE 1 +#define MODE_SELECT 2 +#define MODE_UPDATE 3 +#define MODE_DELETE 4 +#define MODE_QUERY 5 + +int main(int argc, char **argv){ + const char *zFileToRead = 0; /* Input file. NULL for stdin */ + const char *zDbName = 0; /* Name of the database file to create */ + int useWithoutRowid = 0; /* True for --without-rowid */ + int iMode = MODE_INSERT; /* One of MODE_xxxxx */ + int useNocase = 0; /* True for --nocase */ + int doTrace = 0; /* True for --trace */ + int showStats = 0; /* True for --stats */ + int showSummary = 0; /* True for --summary */ + int showTimer = 0; /* True for --timer */ + int cacheSize = 0; /* Desired cache size. 0 means default */ + int pageSize = 0; /* Desired page size. 0 means default */ + int commitInterval = 0; /* How often to commit. 0 means never */ + int noSync = 0; /* True for --nosync */ + const char *zJMode = 0; /* Journal mode */ + int nOp = 0; /* Operation counter */ + int i, j; /* Loop counters */ + sqlite3 *db; /* The SQLite database connection */ + char *zSql; /* Constructed SQL statement */ + sqlite3_stmt *pInsert = 0; /* The INSERT statement */ + sqlite3_stmt *pUpdate = 0; /* The UPDATE statement */ + sqlite3_stmt *pSelect = 0; /* The SELECT statement */ + sqlite3_stmt *pDelete = 0; /* The DELETE statement */ + FILE *in; /* The open input file */ + int rc; /* Return code from an SQLite interface */ + int iCur, iHiwtr; /* Statistics values, current and "highwater" */ + sqlite3_int64 sumCnt = 0; /* Sum in QUERY mode */ + sqlite3_int64 startTime; + char zInput[2000]; /* A single line of input */ + + /* Process command-line arguments */ + for(i=1; i<argc; i++){ + const char *z = argv[i]; + if( z[0]=='-' ){ + do{ z++; }while( z[0]=='-' ); + if( strcmp(z,"without-rowid")==0 ){ + useWithoutRowid = 1; + }else if( strcmp(z,"replace")==0 ){ + iMode = MODE_REPLACE; + }else if( strcmp(z,"select")==0 ){ + iMode = MODE_SELECT; + }else if( strcmp(z,"insert")==0 ){ + iMode = MODE_INSERT; + }else if( strcmp(z,"update")==0 ){ + iMode = MODE_UPDATE; + }else if( strcmp(z,"delete")==0 ){ + iMode = MODE_DELETE; + }else if( strcmp(z,"query")==0 ){ + iMode = MODE_QUERY; + }else if( strcmp(z,"nocase")==0 ){ + useNocase = 1; + }else if( strcmp(z,"trace")==0 ){ + doTrace = 1; + }else if( strcmp(z,"nosync")==0 ){ + noSync = 1; + }else if( strcmp(z,"stats")==0 ){ + showStats = 1; + }else if( strcmp(z,"summary")==0 ){ + showSummary = 1; + }else if( strcmp(z,"timer")==0 ){ + showTimer = i; + }else if( strcmp(z,"cachesize")==0 && i<argc-1 ){ + i++; + cacheSize = atoi(argv[i]); + }else if( strcmp(z,"pagesize")==0 && i<argc-1 ){ + i++; + pageSize = atoi(argv[i]); + }else if( strcmp(z,"commit")==0 && i<argc-1 ){ + i++; + commitInterval = atoi(argv[i]); + }else if( strcmp(z,"journal")==0 && i<argc-1 ){ + zJMode = argv[++i]; + }else{ + fatal_error("unknown option: %s\n", argv[i]); + } + }else if( zDbName==0 ){ + zDbName = argv[i]; + }else if( zFileToRead==0 ){ + zFileToRead = argv[i]; + }else{ + fatal_error("surplus argument: %s\n", argv[i]); + } + } + if( zDbName==0 ){ + fatal_error("Usage: %s [--options] DATABASE [INPUTFILE]\n", argv[0]); + } + startTime = realTime(); + + /* Open the database and the input file */ + if( sqlite3_open(zDbName, &db) ){ + fatal_error("Cannot open database file: %s\n", zDbName); + } + if( zFileToRead ){ + in = fopen(zFileToRead, "rb"); + if( in==0 ){ + fatal_error("Could not open input file \"%s\"\n", zFileToRead); + } + }else{ + in = stdin; + } + + /* Set database connection options */ + if( doTrace ) sqlite3_trace(db, traceCallback, 0); + if( pageSize ){ + zSql = sqlite3_mprintf("PRAGMA page_size=%d", pageSize); + sqlite3_exec(db, zSql, 0, 0, 0); + sqlite3_free(zSql); + } + if( cacheSize ){ + zSql = sqlite3_mprintf("PRAGMA cache_size=%d", cacheSize); + sqlite3_exec(db, zSql, 0, 0, 0); + sqlite3_free(zSql); + } + if( noSync ) sqlite3_exec(db, "PRAGMA synchronous=OFF", 0, 0, 0); + if( zJMode ){ + zSql = sqlite3_mprintf("PRAGMA journal_mode=%s", zJMode); + sqlite3_exec(db, zSql, 0, 0, 0); + sqlite3_free(zSql); + } + + + /* Construct the "wordcount" table into which to put the words */ + if( sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, 0) ){ + fatal_error("Could not start a transaction\n"); + } + zSql = sqlite3_mprintf( + "CREATE TABLE IF NOT EXISTS wordcount(\n" + " word TEXT PRIMARY KEY COLLATE %s,\n" + " cnt INTEGER\n" + ")%s", + useNocase ? "nocase" : "binary", + useWithoutRowid ? " WITHOUT ROWID" : "" + ); + if( zSql==0 ) fatal_error("out of memory\n"); + rc = sqlite3_exec(db, zSql, 0, 0, 0); + if( rc ) fatal_error("Could not create the wordcount table: %s.\n", + sqlite3_errmsg(db)); + sqlite3_free(zSql); + + /* Prepare SQL statements that will be needed */ + if( iMode==MODE_QUERY ){ + rc = sqlite3_prepare_v2(db, + "SELECT cnt FROM wordcount WHERE word=?1", + -1, &pSelect, 0); + if( rc ) fatal_error("Could not prepare the SELECT statement: %s\n", + sqlite3_errmsg(db)); + } + if( iMode==MODE_SELECT ){ + rc = sqlite3_prepare_v2(db, + "SELECT 1 FROM wordcount WHERE word=?1", + -1, &pSelect, 0); + if( rc ) fatal_error("Could not prepare the SELECT statement: %s\n", + sqlite3_errmsg(db)); + rc = sqlite3_prepare_v2(db, + "INSERT INTO wordcount(word,cnt) VALUES(?1,1)", + -1, &pInsert, 0); + if( rc ) fatal_error("Could not prepare the INSERT statement: %s\n", + sqlite3_errmsg(db)); + } + if( iMode==MODE_SELECT || iMode==MODE_UPDATE || iMode==MODE_INSERT ){ + rc = sqlite3_prepare_v2(db, + "UPDATE wordcount SET cnt=cnt+1 WHERE word=?1", + -1, &pUpdate, 0); + if( rc ) fatal_error("Could not prepare the UPDATE statement: %s\n", + sqlite3_errmsg(db)); + } + if( iMode==MODE_INSERT ){ + rc = sqlite3_prepare_v2(db, + "INSERT OR IGNORE INTO wordcount(word,cnt) VALUES(?1,1)", + -1, &pInsert, 0); + if( rc ) fatal_error("Could not prepare the INSERT statement: %s\n", + sqlite3_errmsg(db)); + } + if( iMode==MODE_UPDATE ){ + rc = sqlite3_prepare_v2(db, + "INSERT OR IGNORE INTO wordcount(word,cnt) VALUES(?1,0)", + -1, &pInsert, 0); + if( rc ) fatal_error("Could not prepare the INSERT statement: %s\n", + sqlite3_errmsg(db)); + } + if( iMode==MODE_REPLACE ){ + rc = sqlite3_prepare_v2(db, + "REPLACE INTO wordcount(word,cnt)" + "VALUES(?1,coalesce((SELECT cnt FROM wordcount WHERE word=?1),0)+1)", + -1, &pInsert, 0); + if( rc ) fatal_error("Could not prepare the REPLACE statement: %s\n", + sqlite3_errmsg(db)); + } + if( iMode==MODE_DELETE ){ + rc = sqlite3_prepare_v2(db, + "DELETE FROM wordcount WHERE word=?1", + -1, &pDelete, 0); + if( rc ) fatal_error("Could not prepare the DELETE statement: %s\n", + sqlite3_errmsg(db)); + } + + /* Process the input file */ + while( fgets(zInput, sizeof(zInput), in) ){ + for(i=0; zInput[i]; i++){ + if( !isalpha(zInput[i]) ) continue; + for(j=i+1; isalpha(zInput[j]); j++){} + + /* Found a new word at zInput[i] that is j-i bytes long. + ** Process it into the wordcount table. */ + if( iMode==MODE_DELETE ){ + sqlite3_bind_text(pDelete, 1, zInput+i, j-i, SQLITE_STATIC); + if( sqlite3_step(pDelete)!=SQLITE_DONE ){ + fatal_error("DELETE failed: %s\n", sqlite3_errmsg(db)); + } + sqlite3_reset(pDelete); + }else if( iMode==MODE_SELECT ){ + sqlite3_bind_text(pSelect, 1, zInput+i, j-i, SQLITE_STATIC); + rc = sqlite3_step(pSelect); + sqlite3_reset(pSelect); + if( rc==SQLITE_ROW ){ + sqlite3_bind_text(pUpdate, 1, zInput+i, j-i, SQLITE_STATIC); + if( sqlite3_step(pUpdate)!=SQLITE_DONE ){ + fatal_error("UPDATE failed: %s\n", sqlite3_errmsg(db)); + } + sqlite3_reset(pUpdate); + }else if( rc==SQLITE_DONE ){ + sqlite3_bind_text(pInsert, 1, zInput+i, j-i, SQLITE_STATIC); + if( sqlite3_step(pInsert)!=SQLITE_DONE ){ + fatal_error("Insert failed: %s\n", sqlite3_errmsg(db)); + } + sqlite3_reset(pInsert); + }else{ + fatal_error("SELECT failed: %s\n", sqlite3_errmsg(db)); + } + }else if( iMode==MODE_QUERY ){ + sqlite3_bind_text(pSelect, 1, zInput+i, j-i, SQLITE_STATIC); + if( sqlite3_step(pSelect)==SQLITE_ROW ){ + sumCnt += sqlite3_column_int64(pSelect, 0); + } + sqlite3_reset(pSelect); + }else{ + sqlite3_bind_text(pInsert, 1, zInput+i, j-i, SQLITE_STATIC); + if( sqlite3_step(pInsert)!=SQLITE_DONE ){ + fatal_error("INSERT failed: %s\n", sqlite3_errmsg(db)); + } + sqlite3_reset(pInsert); + if( iMode==MODE_UPDATE + || (iMode==MODE_INSERT && sqlite3_changes(db)==0) + ){ + sqlite3_bind_text(pUpdate, 1, zInput+i, j-i, SQLITE_STATIC); + if( sqlite3_step(pUpdate)!=SQLITE_DONE ){ + fatal_error("UPDATE failed: %s\n", sqlite3_errmsg(db)); + } + sqlite3_reset(pUpdate); + } + } + i = j-1; + + /* Increment the operation counter. Do a COMMIT if it is time. */ + nOp++; + if( commitInterval>0 && (nOp%commitInterval)==0 ){ + sqlite3_exec(db, "COMMIT; BEGIN IMMEDIATE", 0, 0, 0); + } + } + } + sqlite3_exec(db, "COMMIT", 0, 0, 0); + if( zFileToRead ) fclose(in); + sqlite3_finalize(pInsert); + sqlite3_finalize(pUpdate); + sqlite3_finalize(pSelect); + sqlite3_finalize(pDelete); + + if( iMode==MODE_QUERY ){ + printf("sum of cnt: %lld\n", sumCnt); + rc = sqlite3_prepare_v2(db,"SELECT sum(cnt*cnt) FROM wordcount", -1, + &pSelect, 0); + if( rc==SQLITE_OK && sqlite3_step(pSelect)==SQLITE_ROW ){ + printf("double-check: %lld\n", sqlite3_column_int64(pSelect, 0)); + } + sqlite3_finalize(pSelect); + } + + + if( showTimer ){ + sqlite3_int64 elapseTime = realTime() - startTime; + fprintf(stderr, "%3d.%03d wordcount", (int)(elapseTime/1000), + (int)(elapseTime%1000)); + for(i=1; i<argc; i++) if( i!=showTimer ) fprintf(stderr, " %s", argv[i]); + fprintf(stderr, "\n"); + } + + if( showSummary ){ + sqlite3_create_function(db, "checksum", -1, SQLITE_UTF8, 0, + 0, checksumStep, checksumFinalize); + sqlite3_exec(db, + "SELECT 'count(*): ', count(*) FROM wordcount;\n" + "SELECT 'sum(cnt): ', sum(cnt) FROM wordcount;\n" + "SELECT 'max(cnt): ', max(cnt) FROM wordcount;\n" + "SELECT 'avg(cnt): ', avg(cnt) FROM wordcount;\n" + "SELECT 'sum(cnt=1):', sum(cnt=1) FROM wordcount;\n" + "SELECT 'top 10: ', group_concat(word, ', ') FROM " + "(SELECT word FROM wordcount ORDER BY cnt DESC, word LIMIT 10);\n" + "SELECT 'checksum: ', checksum(word, cnt) FROM " + "(SELECT word, cnt FROM wordcount ORDER BY word);\n" + "PRAGMA integrity_check;\n", + printResult, 0, 0); + } + + /* Database connection statistics printed after both prepared statements + ** have been finalized */ + if( showStats ){ + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, 0); + printf("-- Lookaside Slots Used: %d (max %d)\n", iCur,iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, 0); + printf("-- Successful lookasides: %d\n", iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur,&iHiwtr,0); + printf("-- Lookaside size faults: %d\n", iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur,&iHiwtr,0); + printf("-- Lookaside OOM faults: %d\n", iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, 0); + printf("-- Pager Heap Usage: %d bytes\n", iCur); + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); + printf("-- Page cache hits: %d\n", iCur); + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1); + printf("-- Page cache misses: %d\n", iCur); + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1); + printf("-- Page cache writes: %d\n", iCur); + sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, 0); + printf("-- Schema Heap Usage: %d bytes\n", iCur); + sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, 0); + printf("-- Statement Heap Usage: %d bytes\n", iCur); + } + + sqlite3_close(db); + + /* Global memory usage statistics printed after the database connection + ** has closed. Memory usage should be zero at this point. */ + if( showStats ){ + sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, 0); + printf("-- Memory Used (bytes): %d (max %d)\n", iCur,iHiwtr); + sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, 0); + printf("-- Outstanding Allocations: %d (max %d)\n", iCur,iHiwtr); + sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, 0); + printf("-- Pcache Overflow Bytes: %d (max %d)\n", iCur,iHiwtr); + sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, 0); + printf("-- Scratch Overflow Bytes: %d (max %d)\n", iCur,iHiwtr); + sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, 0); + printf("-- Largest Allocation: %d bytes\n",iHiwtr); + sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, 0); + printf("-- Largest Pcache Allocation: %d bytes\n",iHiwtr); + sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, 0); + printf("-- Largest Scratch Allocation: %d bytes\n", iHiwtr); + } + return 0; +} diff --git a/test/zerodamage.test b/test/zerodamage.test index de5088b..dccaba8 100644 --- a/test/zerodamage.test +++ b/test/zerodamage.test @@ -115,7 +115,7 @@ ifcapable wal { UPDATE t1 SET y=randomblob(50) WHERE x=124; } file size test.db-wal - } {8416} + } {16800} } finish_test |