Merge branch 'sqlite-release' into release-integration

This commit is contained in:
Stephen Lombardo
2011-08-17 13:18:08 -04:00
137 changed files with 11121 additions and 3202 deletions
+197
View File
@@ -0,0 +1,197 @@
# 2011 May 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.
#
#***********************************************************************
#
# Test cases for the SQLITE_ENABLE_8_3_NAMES feature that forces all
# filename extensions to be limited to 3 characters. Some embedded
# systems need this to work around microsoft FAT patents, but this
# feature should be disabled on most deployments.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !8_3_names {
finish_test
return
}
db close
sqlite3_shutdown
sqlite3_config_uri 1
do_test 8_3_names-1.0 {
forcedelete test.db test.nal test.db-journal
sqlite3 db test.db
db eval {
PRAGMA cache_size=10;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(randomblob(20000));
BEGIN;
DELETE FROM t1;
INSERT INTO t1 VALUES(randomblob(15000));
}
file exists test.db-journal
} 1
do_test 8_3_names-1.1 {
file exists test.nal
} 0
do_test 8_3_names-1.2 {
db eval {
ROLLBACK;
SELECT length(x) FROM t1
}
} 20000
db close
do_test 8_3_names-2.0 {
forcedelete test.db test.nal test.db-journal
sqlite3 db file:./test.db?8_3_names=1
db eval {
PRAGMA cache_size=10;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(randomblob(20000));
BEGIN;
DELETE FROM t1;
INSERT INTO t1 VALUES(randomblob(15000));
}
file exists test.db-journal
} 0
do_test 8_3_names-2.1 {
file exists test.nal
} 1
forcedelete test2.db test2.nal test2.db-journal
file copy test.db test2.db
file copy test.nal test2.nal
do_test 8_3_names-2.2 {
db eval {
COMMIT;
SELECT length(x) FROM t1
}
} 15000
do_test 8_3_names-2.3 {
sqlite3 db2 file:./test2.db?8_3_names=1
db2 eval {
PRAGMA integrity_check;
SELECT length(x) FROM t1;
}
} {ok 20000}
db close
do_test 8_3_names-3.0 {
forcedelete test.db test.nal test.db-journal
sqlite3 db file:./test.db?8_3_names=0
db eval {
PRAGMA cache_size=10;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(randomblob(20000));
BEGIN;
DELETE FROM t1;
INSERT INTO t1 VALUES(randomblob(15000));
}
file exists test.db-journal
} 1
do_test 8_3_names-3.1 {
file exists test.nal
} 0
forcedelete test2.db test2.nal test2.db-journal
file copy test.db test2.db
file copy test.db-journal test2.db-journal
do_test 8_3_names-3.2 {
db eval {
COMMIT;
SELECT length(x) FROM t1
}
} 15000
do_test 8_3_names-3.3 {
sqlite3 db2 file:./test2.db?8_3_names=0
db2 eval {
PRAGMA integrity_check;
SELECT length(x) FROM t1;
}
} {ok 20000}
##########################################################################
# Master journals.
#
db close
forcedelete test.db test2.db
do_test 8_3_names-4.0 {
sqlite3 db file:./test.db?8_3_names=1
db eval {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1);
ATTACH 'file:./test2.db?8_3_names=1' AS db2;
CREATE TABLE db2.t2(y);
INSERT INTO t2 VALUES(2);
BEGIN;
INSERT INTO t1 VALUES(3);
INSERT INTO t2 VALUES(4);
COMMIT;
SELECT * FROM t1, t2 ORDER BY x, y
}
} {1 2 1 4 3 2 3 4}
##########################################################################
# WAL mode.
#
ifcapable !wal {
finish_test
return
}
db close
forcedelete test.db
do_test 8_3_names-5.0 {
sqlite3 db file:./test.db?8_3_names=1
register_wholenumber_module db
db eval {
PRAGMA journal_mode=WAL;
CREATE TABLE t1(x);
CREATE VIRTUAL TABLE nums USING wholenumber;
INSERT INTO t1 SELECT value FROM nums WHERE value BETWEEN 1 AND 1000;
BEGIN;
UPDATE t1 SET x=x*2;
}
sqlite3 db2 file:./test.db?8_3_names=1
register_wholenumber_module db2
db2 eval {
BEGIN;
SELECT sum(x) FROM t1;
}
} {500500}
do_test 8_3_names-5.1 {
file exists test.db-wal
} 0
do_test 8_3_names-5.2 {
file exists test.wal
} 1
do_test 8_3_names-5.3 {
file exists test.db-shm
} 0
do_test 8_3_names-5.4 {
file exists test.shm
} 1
do_test 8_3_names-5.5 {
db eval {
COMMIT;
SELECT sum(x) FROM t1;
}
} {1001000}
do_test 8_3_names-5.6 {
db2 eval {
SELECT sum(x) FROM t1;
}
} {500500}
finish_test
+1 -1
View File
@@ -650,7 +650,7 @@ do_test alter-6.7 {
# Ticket #1665: Make sure ALTER TABLE ADD COLUMN works on a table
# that includes a COLLATE clause.
#
do_test alter-7.1 {
do_realnum_test alter-7.1 {
execsql {
CREATE TABLE t1(a TEXT COLLATE BINARY);
ALTER TABLE t1 ADD COLUMN b INTEGER COLLATE NOCASE;
+5 -5
View File
@@ -234,7 +234,7 @@ do_test cast-3.1 {
do_test cast-3.2 {
execsql {SELECT CAST(9223372036854774800 AS numeric)}
} 9223372036854774800
do_test cast-3.3 {
do_realnum_test cast-3.3 {
execsql {SELECT CAST(9223372036854774800 AS real)}
} 9.22337203685477e+18
do_test cast-3.4 {
@@ -246,7 +246,7 @@ do_test cast-3.5 {
do_test cast-3.6 {
execsql {SELECT CAST(-9223372036854774800 AS numeric)}
} -9223372036854774800
do_test cast-3.7 {
do_realnum_test cast-3.7 {
execsql {SELECT CAST(-9223372036854774800 AS real)}
} -9.22337203685477e+18
do_test cast-3.8 {
@@ -258,7 +258,7 @@ do_test cast-3.11 {
do_test cast-3.12 {
execsql {SELECT CAST('9223372036854774800' AS numeric)}
} 9223372036854774800
do_test cast-3.13 {
do_realnum_test cast-3.13 {
execsql {SELECT CAST('9223372036854774800' AS real)}
} 9.22337203685477e+18
ifcapable long_double {
@@ -272,7 +272,7 @@ do_test cast-3.15 {
do_test cast-3.16 {
execsql {SELECT CAST('-9223372036854774800' AS numeric)}
} -9223372036854774800
do_test cast-3.17 {
do_realnum_test cast-3.17 {
execsql {SELECT CAST('-9223372036854774800' AS real)}
} -9.22337203685477e+18
ifcapable long_double {
@@ -287,7 +287,7 @@ if {[db eval {PRAGMA encoding}]=="UTF-8"} {
do_test cast-3.22 {
execsql {SELECT CAST(x'39323233333732303336383534373734383030' AS numeric)}
} 9223372036854774800
do_test cast-3.23 {
do_realnum_test cast-3.23 {
execsql {SELECT CAST(x'39323233333732303336383534373734383030' AS real)}
} 9.22337203685477e+18
ifcapable long_double {
+3 -3
View File
@@ -989,9 +989,9 @@ do_execsql_test e_createtable-3.7.4 {
SELECT quote(a), quote(b) FROM t6;
} {1 2 'X' 3 1 4 'X' 5}
# EVIDENCE-OF: R-18683-56219 If the default value of a column is
# CURRENT_TIME, CURRENT_DATE or CURRENT_DATETIME, then the value used in
# the new row is a text representation of the current UTC date and/or
# EVIDENCE-OF: R-15363-55230 If the default value of a column is
# CURRENT_TIME, CURRENT_DATE or CURRENT_TIMESTAMP, then the value used
# in the new row is a text representation of the current UTC date and/or
# time.
#
# This is difficult to test literally without knowing what time the
+1 -1
View File
@@ -440,7 +440,7 @@ do_delete_tests e_delete-3.9 -repair rebuild_t1 -query {
}
# EVIDENCE-OF: R-26627-30313 The ORDER BY clause on an DELETE statement
# EVIDENCE-OF: R-07548-13422 The ORDER BY clause on a DELETE statement
# is used only to determine which rows fall within the LIMIT. The order
# in which rows are deleted is arbitrary and is not influenced by the
# ORDER BY clause.
+2 -3
View File
@@ -1598,8 +1598,8 @@ 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-06126-36021 If an REAL is too large to be represented
# as an INTEGER then the result of the cast is the largest negative
# 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.
#
do_expr_test e_expr-31.2.1 { CAST(2e+50 AS INT) } integer -9223372036854775808
@@ -1845,4 +1845,3 @@ foreach {tn expr} {
finish_test
+1 -1
View File
@@ -152,7 +152,7 @@ do_insert_tests e_insert-1.2 -error {
4 "INSERT INTO a2 VALUES(1,2,3,4,5)" {a2 3 5}
}
# EVIDENCE-OF: R-52422-65517 In this case the result of evaluting the
# EVIDENCE-OF: R-04006-57648 In this case the result of evaluating the
# left-most expression in the VALUES list is inserted into the left-most
# column of the new row, and so on.
#
+3 -3
View File
@@ -1768,9 +1768,9 @@ do_select_tests e_select-8.5 {
}
}
# EVIDENCE-OF: R-27923-38747 Otherwise, if the ORDER BY expression is
# any other expression, it is evaluated and the the returned value used
# to order the output rows.
# EVIDENCE-OF: R-65068-27207 Otherwise, if the ORDER BY expression is
# any other expression, it is evaluated and the returned value used to
# order the output rows.
#
# EVIDENCE-OF: R-03421-57988 If the SELECT statement is a simple SELECT,
# then an ORDER BY may contain any arbitrary expressions.
+2 -3
View File
@@ -233,9 +233,9 @@ do_update_tests e_update-1.5 -query {
{3 1 4 1 5 9 2 6 5}
}
# EVIDENCE-OF: R-09060-20018 If a single column-name appears more than
# EVIDENCE-OF: R-34751-18293 If a single column-name appears more than
# once in the list of assignment expressions, all but the rightmost
# occurence is ignored.
# occurrence is ignored.
#
do_update_tests e_update-1.6 -query {
SELECT * FROM t2
@@ -605,4 +605,3 @@ do_update_tests e_update-3.5 -query { SELECT x FROM t8 ; DELETE FROM t8 } {
} ;# ifcapable update_delete_limit
finish_test
+456
View File
@@ -0,0 +1,456 @@
# 2011 May 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix e_uri
db close
proc parse_uri {uri} {
testvfs tvfs2
testvfs tvfs
tvfs filter xOpen
tvfs script parse_uri_open_cb
set ::uri_open [list]
set DB [sqlite3_open_v2 $uri {
SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_WAL
} tvfs]
sqlite3_close $DB
tvfs delete
tvfs2 delete
set ::uri_open
}
proc parse_uri_open_cb {method file arglist} {
set ::uri_open [list $file $arglist]
}
proc open_uri_error {uri} {
set flags {SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_WAL}
set DB [sqlite3_open_v2 $uri $flags ""]
set e [sqlite3_errmsg $DB]
sqlite3_close $DB
set e
}
# EVIDENCE-OF: R-35840-33204 If URI filename interpretation is enabled,
# and the filename argument begins with "file:", then the filename is
# interpreted as a URI.
#
# EVIDENCE-OF: R-24124-56960 URI filename interpretation is enabled if
# the SQLITE_OPEN_URI flag is set in the fourth argument to
# sqlite3_open_v2(), or if it has been enabled globally using the
# SQLITE_CONFIG_URI option with the sqlite3_config() method or by the
# SQLITE_USE_URI compile-time option.
#
if {$tcl_platform(platform) == "unix"} {
set flags [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE]
# Tests with SQLITE_CONFIG_URI configured to false. URI intepretation is
# only enabled if the SQLITE_OPEN_URI flag is specified.
sqlite3_shutdown
sqlite3_config_uri 0
do_test 1.1 {
forcedelete file:test.db test.db
set DB [sqlite3_open_v2 file:test.db [concat $flags SQLITE_OPEN_URI] ""]
list [file exists file:test.db] [file exists test.db]
} {0 1}
do_test 1.2 {
forcedelete file:test.db2 test.db2
set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy]
sqlite3_step $STMT
sqlite3_finalize $STMT
list [file exists file:test.db2] [file exists test.db2]
} {0 1}
sqlite3_close $DB
do_test 1.3 {
forcedelete file:test.db test.db
set DB [sqlite3_open_v2 file:test.db [concat $flags] ""]
list [file exists file:test.db] [file exists test.db]
} {1 0}
do_test 1.4 {
forcedelete file:test.db2 test.db2
set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy]
sqlite3_step $STMT
sqlite3_finalize $STMT
list [file exists file:test.db2] [file exists test.db2]
} {1 0}
sqlite3_close $DB
# Tests with SQLITE_CONFIG_URI configured to true. URI intepretation is
# enabled with or without SQLITE_OPEN_URI.
#
sqlite3_shutdown
sqlite3_config_uri 1
do_test 1.5 {
forcedelete file:test.db test.db
set DB [sqlite3_open_v2 file:test.db [concat $flags SQLITE_OPEN_URI] ""]
list [file exists file:test.db] [file exists test.db]
} {0 1}
do_test 1.6 {
forcedelete file:test.db2 test.db2
set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy]
sqlite3_step $STMT
sqlite3_finalize $STMT
list [file exists file:test.db2] [file exists test.db2]
} {0 1}
sqlite3_close $DB
do_test 1.7 {
forcedelete file:test.db test.db
set DB [sqlite3_open_v2 file:test.db [concat $flags] ""]
list [file exists file:test.db] [file exists test.db]
} {0 1}
do_test 1.8 {
forcedelete file:test.db2 test.db2
set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy]
sqlite3_step $STMT
sqlite3_finalize $STMT
list [file exists file:test.db2] [file exists test.db2]
} {0 1}
sqlite3_close $DB
}
# ensure uri processing enabled for the rest of the tests
sqlite3_shutdown
sqlite3_config_uri 1
# EVIDENCE-OF: R-17482-00398 If the authority is not an empty string or
# "localhost", an error is returned to the caller.
#
if {$tcl_platform(platform) == "unix"} {
set flags [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI]
foreach {tn uri error} "
1 {file://localhost[pwd]/test.db} {not an error}
2 {file://[pwd]/test.db} {not an error}
3 {file://x[pwd]/test.db} {invalid uri authority: x}
4 {file://invalid[pwd]/test.db} {invalid uri authority: invalid}
" {
do_test 2.$tn {
set DB [sqlite3_open_v2 $uri $flags ""]
set e [sqlite3_errmsg $DB]
sqlite3_close $DB
set e
} $error
}
}
# EVIDENCE-OF: R-45981-25528 The fragment component of a URI, if
# present, is ignored.
#
# It is difficult to test that something is ignored correctly. So these tests
# just show that adding a fragment does not interfere with the pathname or
# parameters passed through to the VFS xOpen() methods.
#
foreach {tn uri parse} "
1 {file:test.db#abc} {[pwd]/test.db {}}
2 {file:test.db?a=b#abc} {[pwd]/test.db {a b}}
3 {file:test.db?a=b#?c=d} {[pwd]/test.db {a b}}
" {
do_filepath_test 3.$tn { parse_uri $uri } $parse
}
# EVIDENCE-OF: R-62557-09390 SQLite uses the path component of the URI
# as the name of the disk file which contains the database.
#
# EVIDENCE-OF: R-28659-11035 If the path begins with a '/' character,
# then it is interpreted as an absolute path.
#
# EVIDENCE-OF: R-46234-61323 If the path does not begin with a '/'
# (meaning that the authority section is omitted from the URI) then the
# path is interpreted as a relative path.
#
foreach {tn uri parse} "
1 {file:test.db} {[pwd]/test.db {}}
2 {file:/test.db} {/test.db {}}
3 {file:///test.db} {/test.db {}}
4 {file://localhost/test.db} {/test.db {}}
5 {file:/a/b/c/test.db} {/a/b/c/test.db {}}
" {
do_filepath_test 4.$tn { parse_uri $uri } $parse
}
# EVIDENCE-OF: R-01612-30877 The "vfs" parameter may be used to specify
# the name of a VFS object that provides the operating system interface
# that should be used to access the database file on disk.
#
# The above is tested by cases 1.* below.
#
# EVIDENCE-OF: R-52293-58497 If this option is set to an empty string
# the default VFS object is used.
#
# The above is tested by cases 2.* below.
#
# EVIDENCE-OF: R-31855-18665 If sqlite3_open_v2() is used and the vfs
# option is present, then the VFS specified by the option takes
# precedence over the value passed as the fourth parameter to
# sqlite3_open_v2().
#
# The above is tested by cases 3.* below.
#
proc vfs_open_cb {name args} {
set ::vfs $name
}
foreach {name default} {vfs1 0 vfs2 0 vfs3 1} {
testvfs $name -default $default
$name filter xOpen
$name script [list vfs_open_cb $name]
}
foreach {tn uri defvfs vfs} {
1.1 "file:test.db?vfs=vfs1" "" vfs1
1.2 "file:test.db?vfs=vfs2" "" vfs2
2.1 "file:test.db" vfs1 vfs1
2.2 "file:test.db?vfs=" vfs1 vfs3
3.1 "file:test.db?vfs=vfs1" vfs2 vfs1
3.2 "file:test.db?vfs=vfs2" vfs1 vfs2
3.3 "file:test.db?xvfs=vfs1" vfs2 vfs2
3.4 "file:test.db?xvfs=vfs2" vfs1 vfs1
} {
do_test 5.$tn {
set flags [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI]
sqlite3_close [
sqlite3_open_v2 $uri $flags $defvfs
]
set ::vfs
} $vfs
}
vfs1 delete
vfs2 delete
vfs3 delete
# EVIDENCE-OF: R-48365-36308 Specifying an unknown VFS is an error.
#
set flags [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI]
do_test 6.1 {
set DB [sqlite3_open_v2 file:test.db?vfs=nosuchvfs $flags ""]
set errmsg [sqlite3_errmsg $DB]
sqlite3_close $DB
set errmsg
} {no such vfs: nosuchvfs}
# EVIDENCE-OF: R-60479-64270 The mode parameter may be set to either
# "ro", "rw" or "rwc". Attempting to set it to any other value is an
# error
#
sqlite3 db test.db
db close
foreach {tn uri error} "
1 {file:test.db?mode=ro} {not an error}
2 {file:test.db?mode=rw} {not an error}
3 {file:test.db?mode=rwc} {not an error}
4 {file:test.db?mode=Ro} {no such access mode: Ro}
5 {file:test.db?mode=Rw} {no such access mode: Rw}
6 {file:test.db?mode=Rwc} {no such access mode: Rwc}
" {
do_test 7.$tn { open_uri_error $uri } $error
}
# EVIDENCE-OF: R-09651-31805 If "ro" is specified, then the database is
# opened for read-only access, just as if the SQLITE_OPEN_READONLY flag
# had been set in the third argument to sqlite3_prepare_v2().
#
# EVIDENCE-OF: R-40137-26050 If the mode option is set to "rw", then the
# database is opened for read-write (but not create) access, as if
# SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had been set.
#
# EVIDENCE-OF: R-26845-32976 Value "rwc" is equivalent to setting both
# SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE.
#
foreach {tn uri read write create} {
1 {file:test.db?mode=ro} 1 0 0
2 {file:test.db?mode=rw} 1 1 0
3 {file:test.db?mode=rwc} 1 1 1
} {
set RES(c,0) {1 {unable to open database file}}
set RES(c,1) {0 {}}
set RES(w,0) {1 {attempt to write a readonly database}}
set RES(w,1) {0 {}}
set RES(r,0) {1 {this never happens}}
set RES(r,1) {0 {a b}}
# Test CREATE access:
forcedelete test.db
do_test 8.$tn.c { list [catch { sqlite3 db $uri } msg] $msg } $RES(c,$create)
catch { db close }
sqlite3 db test.db
db eval { CREATE TABLE t1(a, b) ; INSERT INTO t1 VALUES('a', 'b') ;}
db close
# Test READ access:
do_test 8.$tn.r {
sqlite3 db $uri
catchsql { SELECT * FROM t1 }
} $RES(r,$read)
# Test WRITE access:
do_test 8.$tn.w {
sqlite3 db $uri
catchsql { INSERT INTO t1 VALUES(1, 2) }
} $RES(w,$write)
catch {db close}
}
# EVIDENCE-OF: R-56032-32287 If sqlite3_open_v2() is used, it is an
# error to specify a value for the mode parameter that is less
# restrictive than that specified by the flags passed as the third
# parameter.
#
forcedelete test.db
sqlite3 db test.db
db close
foreach {tn uri flags error} {
1 {file:test.db?mode=ro} ro {not an error}
2 {file:test.db?mode=ro} rw {not an error}
3 {file:test.db?mode=ro} rwc {not an error}
4 {file:test.db?mode=rw} ro {access mode not allowed: rw}
5 {file:test.db?mode=rw} rw {not an error}
6 {file:test.db?mode=rw} rwc {not an error}
7 {file:test.db?mode=rwc} ro {access mode not allowed: rwc}
8 {file:test.db?mode=rwc} rw {access mode not allowed: rwc}
9 {file:test.db?mode=rwc} rwc {not an error}
} {
set f(ro) [list SQLITE_OPEN_READONLY SQLITE_OPEN_URI]
set f(rw) [list SQLITE_OPEN_READWRITE SQLITE_OPEN_URI]
set f(rwc) [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI]
set DB [sqlite3_open_v2 $uri $f($flags) ""]
set e [sqlite3_errmsg $DB]
sqlite3_close $DB
do_test 9.$tn { set e } $error
}
# EVIDENCE-OF: R-23182-54295 The cache parameter may be set to either
# "shared" or "private".
sqlite3 db test.db
db close
foreach {tn uri error} "
1 {file:test.db?cache=private} {not an error}
2 {file:test.db?cache=shared} {not an error}
3 {file:test.db?cache=yes} {no such cache mode: yes}
4 {file:test.db?cache=} {no such cache mode: }
" {
do_test 10.$tn { open_uri_error $uri } $error
}
# EVIDENCE-OF: R-23027-03515 Setting it to "shared" is equivalent to
# setting the SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed
# to sqlite3_open_v2().
#
# 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
# "cache" parameter is present in a URI filename, its value overrides
# any behaviour requested by setting SQLITE_OPEN_PRIVATECACHE or
# SQLITE_OPEN_SHAREDCACHE flag.
#
set orig [sqlite3_enable_shared_cache]
foreach {tn uri flags shared_default isshared} {
1.1 "file:test.db" "" 0 0
1.2 "file:test.db" "" 1 1
1.3 "file:test.db" private 0 0
1.4 "file:test.db" private 1 0
1.5 "file:test.db" shared 0 1
1.6 "file:test.db" shared 1 1
2.1 "file:test.db?cache=private" "" 0 0
2.2 "file:test.db?cache=private" "" 1 0
2.3 "file:test.db?cache=private" private 0 0
2.4 "file:test.db?cache=private" private 1 0
2.5 "file:test.db?cache=private" shared 0 0
2.6 "file:test.db?cache=private" shared 1 0
3.1 "file:test.db?cache=shared" "" 0 1
3.2 "file:test.db?cache=shared" "" 1 1
3.3 "file:test.db?cache=shared" private 0 1
3.4 "file:test.db?cache=shared" private 1 1
3.5 "file:test.db?cache=shared" shared 0 1
3.6 "file:test.db?cache=shared" shared 1 1
} {
forcedelete test.db
sqlite3_enable_shared_cache 1
sqlite3 db test.db
sqlite3_enable_shared_cache 0
db eval {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('ok');
}
unset -nocomplain f
set f() {SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI}
set f(shared) [concat $f() SQLITE_OPEN_SHAREDCACHE]
set f(private) [concat $f() SQLITE_OPEN_PRIVATECACHE]
sqlite3_enable_shared_cache $shared_default
set DB [sqlite3_open_v2 $uri $f($flags) ""]
set STMT [sqlite3_prepare $DB "SELECT * FROM t1" -1 dummy]
db eval {
BEGIN;
INSERT INTO t1 VALUES('ko');
}
sqlite3_step $STMT
sqlite3_finalize $STMT
set RES(0) {not an error}
set RES(1) {database table is locked: t1}
do_test 11.$tn { sqlite3_errmsg $DB } $RES($isshared)
sqlite3_close $DB
db close
}
sqlite3_enable_shared_cache $orig
# EVIDENCE-OF: R-63472-46769 Specifying an unknown parameter in the
# query component of a URI is not an error.
#
do_filepath_test 12.1 {
parse_uri file://localhost/test.db?an=unknown&parameter=is&ok=
} {/test.db {an unknown parameter is ok {}}}
do_filepath_test 12.2 {
parse_uri file://localhost/test.db?an&unknown&parameter&is&ok
} {/test.db {an {} unknown {} parameter {} is {} ok {}}}
# EVIDENCE-OF: R-27458-04043 URI hexadecimal escape sequences (%HH) are
# supported within the path and query components of a URI.
#
# EVIDENCE-OF: R-52765-50368 Before the path or query components of a
# URI filename are interpreted, they are encoded using UTF-8 and all
# hexadecimal escape sequences replaced by a single byte containing the
# corresponding octet.
#
# The second of the two statements above is tested by creating a
# multi-byte utf-8 character using a sequence of %HH escapes.
#
foreach {tn uri parse} "
1 {file:/test.%64%62} {/test.db {}}
2 {file:/test.db?%68%65%6c%6c%6f=%77%6f%72%6c%64} {/test.db {hello world}}
3 {file:/%C3%BF.db} {/\xFF.db {}}
" {
do_filepath_test 13.$tn { parse_uri $uri } $parse
}
finish_test
+137 -139
View File
@@ -1,139 +1,137 @@
# 2010 Sept 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. The focus of
# this file is testing the SQLite routines used for converting between the
# various suported unicode encodings (UTF-8, UTF-16, UTF-16le and
# UTF-16be).
#
# $Id: enc4.test,v 1.0 2010/09/29 08:29:32 shaneh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If UTF16 support is disabled, ignore the tests in this file
#
ifcapable {!utf16} {
finish_test
return
}
db close
# The three unicode encodings understood by SQLite.
set encodings [list UTF-8 UTF-16le UTF-16be]
# initial value to use in SELECT
set inits [list 1 1.0 1. 1e0]
# vals
set vals [list\
"922337203685477580792233720368547758079223372036854775807"\
"100000000000000000000000000000000000000000000000000000000"\
"1.0000000000000000000000000000000000000000000000000000000"\
]
set i 1
foreach enc $encodings {
file delete -force test.db
sqlite3 db test.db
db eval "PRAGMA encoding = \"$enc\""
do_test enc4-$i.1 {
db eval {PRAGMA encoding}
} $enc
set j 1
foreach init $inits {
do_test enc4-$i.$j.2 {
set S [sqlite3_prepare_v2 db "SELECT $init+?" -1 dummy]
sqlite3_expired $S
} {0}
set k 1
foreach val $vals {
for {set x 1} {$x<18} {incr x} {
set part [expr $init + [string range $val 0 [expr $x-1]]]
regsub {e\+0} $part {e+} part
regsub {^1e} $part {1.0e} part
do_test enc4-$i.$j.$k.3.$x {
sqlite3_reset $S
sqlite3_bind_text $S 1 $val $x
sqlite3_step $S
sqlite3_column_text $S 0
} [list $part]
do_test enc4-$i.$j.$k.4.$x {
sqlite3_reset $S
sqlite3_bind_text16 $S 1 [encoding convertto unicode $val] [expr $x*2]
sqlite3_step $S
sqlite3_column_text $S 0
} [list $part]
}
incr k
}
do_test enc4-$i.$j.5 {
sqlite3_finalize $S
} {SQLITE_OK}
incr j
}
db close
incr i
}
file delete -force test.db
sqlite3 db test.db
do_test enc4-4.1 {
db eval "select 1+1."
} {2.0}
do_test enc4-4.2.1 {
set S [sqlite3_prepare_v2 db "SELECT 1+1." -1 dummy]
sqlite3_step $S
sqlite3_column_text $S 0
} {2.0}
do_test enc4-4.2.2 {
sqlite3_finalize $S
} {SQLITE_OK}
do_test enc4-4.3.1 {
set S [sqlite3_prepare_v2 db "SELECT 1+?" -1 dummy]
sqlite3_bind_text $S 1 "1." 2
sqlite3_step $S
sqlite3_column_text $S 0
} {2.0}
do_test enc4-4.3.2 {
sqlite3_finalize $S
} {SQLITE_OK}
do_test enc4-4.4.1 {
set S [sqlite3_prepare_v2 db "SELECT 1+?" -1 dummy]
sqlite3_bind_text $S 1 "1.0" 2
sqlite3_step $S
sqlite3_column_text $S 0
} {2.0}
do_test enc4-4.4.2 {
sqlite3_finalize $S
} {SQLITE_OK}
db close
finish_test
# 2010 Sept 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. The focus of
# this file is testing the SQLite routines used for converting between the
# various suported unicode encodings (UTF-8, UTF-16, UTF-16le and
# UTF-16be).
#
# $Id: enc4.test,v 1.0 2010/09/29 08:29:32 shaneh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If UTF16 support is disabled, ignore the tests in this file
#
ifcapable {!utf16} {
finish_test
return
}
db close
# The three unicode encodings understood by SQLite.
set encodings [list UTF-8 UTF-16le UTF-16be]
# initial value to use in SELECT
set inits [list 1 1.0 1. 1e0]
# vals
set vals [list\
"922337203685477580792233720368547758079223372036854775807"\
"100000000000000000000000000000000000000000000000000000000"\
"1.0000000000000000000000000000000000000000000000000000000"\
]
set i 1
foreach enc $encodings {
file delete -force test.db
sqlite3 db test.db
db eval "PRAGMA encoding = \"$enc\""
do_test enc4-$i.1 {
db eval {PRAGMA encoding}
} $enc
set j 1
foreach init $inits {
do_test enc4-$i.$j.2 {
set S [sqlite3_prepare_v2 db "SELECT $init+?" -1 dummy]
sqlite3_expired $S
} {0}
set k 1
foreach val $vals {
for {set x 1} {$x<16} {incr x} {
set part [expr $init + [string range $val 0 [expr $x-1]]]
do_realnum_test enc4-$i.$j.$k.3.$x {
sqlite3_reset $S
sqlite3_bind_text $S 1 $val $x
sqlite3_step $S
sqlite3_column_text $S 0
} [list $part]
do_realnum_test enc4-$i.$j.$k.4.$x {
sqlite3_reset $S
sqlite3_bind_text16 $S 1 [encoding convertto unicode $val] [expr $x*2]
sqlite3_step $S
sqlite3_column_text $S 0
} [list $part]
}
incr k
}
do_test enc4-$i.$j.5 {
sqlite3_finalize $S
} {SQLITE_OK}
incr j
}
db close
incr i
}
file delete -force test.db
sqlite3 db test.db
do_test enc4-4.1 {
db eval "select 1+1."
} {2.0}
do_test enc4-4.2.1 {
set S [sqlite3_prepare_v2 db "SELECT 1+1." -1 dummy]
sqlite3_step $S
sqlite3_column_text $S 0
} {2.0}
do_test enc4-4.2.2 {
sqlite3_finalize $S
} {SQLITE_OK}
do_test enc4-4.3.1 {
set S [sqlite3_prepare_v2 db "SELECT 1+?" -1 dummy]
sqlite3_bind_text $S 1 "1." 2
sqlite3_step $S
sqlite3_column_text $S 0
} {2.0}
do_test enc4-4.3.2 {
sqlite3_finalize $S
} {SQLITE_OK}
do_test enc4-4.4.1 {
set S [sqlite3_prepare_v2 db "SELECT 1+?" -1 dummy]
sqlite3_bind_text $S 1 "1.0" 2
sqlite3_step $S
sqlite3_column_text $S 0
} {2.0}
do_test enc4-4.4.2 {
sqlite3_finalize $S
} {SQLITE_OK}
db close
finish_test
+58 -53
View File
@@ -32,6 +32,11 @@ proc test_expr {name settings expr result} {
execsql {BEGIN; UPDATE test1 SET %s; SELECT %s FROM test1; ROLLBACK;}
} $settings $expr] $result
}
proc test_realnum_expr {name settings expr result} {
do_realnum_test $name [format {
execsql {BEGIN; UPDATE test1 SET %s; SELECT %s FROM test1; ROLLBACK;}
} $settings $expr] $result
}
test_expr expr-1.1 {i1=10, i2=20} {i1+i2} 30
test_expr expr-1.2 {i1=10, i2=20} {i1-i2} -10
@@ -164,7 +169,7 @@ ifcapable floatingpoint {
}
if {[working_64bit_int]} {
test_expr expr-1.106 {i1=0} {-9223372036854775808/-1} 9.22337203685478e+18
test_realnum_expr expr-1.106 {i1=0} {-9223372036854775808/-1} 9.22337203685478e+18
}
test_expr expr-1.107 {i1=0} {-9223372036854775808%-1} 0
@@ -203,100 +208,100 @@ test_expr expr-1.126 {i1=8, i2=8} \
ifcapable floatingpoint {if {[working_64bit_int]} {
test_expr expr-1.200\
{i1=9223372036854775806, i2=1} {i1+i2} 9223372036854775807
test_expr expr-1.201\
test_realnum_expr expr-1.201\
{i1=9223372036854775806, i2=2} {i1+i2} 9.22337203685478e+18
test_expr expr-1.202\
test_realnum_expr expr-1.202\
{i1=9223372036854775806, i2=100000} {i1+i2} 9.22337203685488e+18
test_expr expr-1.203\
test_realnum_expr expr-1.203\
{i1=9223372036854775807, i2=0} {i1+i2} 9223372036854775807
test_expr expr-1.204\
test_realnum_expr expr-1.204\
{i1=9223372036854775807, i2=1} {i1+i2} 9.22337203685478e+18
test_expr expr-1.205\
test_realnum_expr expr-1.205\
{i2=9223372036854775806, i1=1} {i1+i2} 9223372036854775807
test_expr expr-1.206\
test_realnum_expr expr-1.206\
{i2=9223372036854775806, i1=2} {i1+i2} 9.22337203685478e+18
test_expr expr-1.207\
test_realnum_expr expr-1.207\
{i2=9223372036854775806, i1=100000} {i1+i2} 9.22337203685488e+18
test_expr expr-1.208\
test_realnum_expr expr-1.208\
{i2=9223372036854775807, i1=0} {i1+i2} 9223372036854775807
test_expr expr-1.209\
test_realnum_expr expr-1.209\
{i2=9223372036854775807, i1=1} {i1+i2} 9.22337203685478e+18
test_expr expr-1.210\
test_realnum_expr expr-1.210\
{i1=-9223372036854775807, i2=-1} {i1+i2} -9223372036854775808
test_expr expr-1.211\
test_realnum_expr expr-1.211\
{i1=-9223372036854775807, i2=-2} {i1+i2} -9.22337203685478e+18
test_expr expr-1.212\
test_realnum_expr expr-1.212\
{i1=-9223372036854775807, i2=-100000} {i1+i2} -9.22337203685488e+18
test_expr expr-1.213\
test_realnum_expr expr-1.213\
{i1=-9223372036854775808, i2=0} {i1+i2} -9223372036854775808
test_expr expr-1.214\
test_realnum_expr expr-1.214\
{i1=-9223372036854775808, i2=-1} {i1+i2} -9.22337203685478e+18
test_expr expr-1.215\
test_realnum_expr expr-1.215\
{i2=-9223372036854775807, i1=-1} {i1+i2} -9223372036854775808
test_expr expr-1.216\
test_realnum_expr expr-1.216\
{i2=-9223372036854775807, i1=-2} {i1+i2} -9.22337203685478e+18
test_expr expr-1.217\
test_realnum_expr expr-1.217\
{i2=-9223372036854775807, i1=-100000} {i1+i2} -9.22337203685488e+18
test_expr expr-1.218\
test_realnum_expr expr-1.218\
{i2=-9223372036854775808, i1=0} {i1+i2} -9223372036854775808
test_expr expr-1.219\
test_realnum_expr expr-1.219\
{i2=-9223372036854775808, i1=-1} {i1+i2} -9.22337203685478e+18
test_expr expr-1.220\
test_realnum_expr expr-1.220\
{i1=9223372036854775806, i2=-1} {i1-i2} 9223372036854775807
test_expr expr-1.221\
test_realnum_expr expr-1.221\
{i1=9223372036854775806, i2=-2} {i1-i2} 9.22337203685478e+18
test_expr expr-1.222\
test_realnum_expr expr-1.222\
{i1=9223372036854775806, i2=-100000} {i1-i2} 9.22337203685488e+18
test_expr expr-1.223\
test_realnum_expr expr-1.223\
{i1=9223372036854775807, i2=0} {i1-i2} 9223372036854775807
test_expr expr-1.224\
test_realnum_expr expr-1.224\
{i1=9223372036854775807, i2=-1} {i1-i2} 9.22337203685478e+18
test_expr expr-1.225\
test_realnum_expr expr-1.225\
{i2=-9223372036854775806, i1=1} {i1-i2} 9223372036854775807
test_expr expr-1.226\
test_realnum_expr expr-1.226\
{i2=-9223372036854775806, i1=2} {i1-i2} 9.22337203685478e+18
test_expr expr-1.227\
test_realnum_expr expr-1.227\
{i2=-9223372036854775806, i1=100000} {i1-i2} 9.22337203685488e+18
test_expr expr-1.228\
test_realnum_expr expr-1.228\
{i2=-9223372036854775807, i1=0} {i1-i2} 9223372036854775807
test_expr expr-1.229\
test_realnum_expr expr-1.229\
{i2=-9223372036854775807, i1=1} {i1-i2} 9.22337203685478e+18
test_expr expr-1.230\
test_realnum_expr expr-1.230\
{i1=-9223372036854775807, i2=1} {i1-i2} -9223372036854775808
test_expr expr-1.231\
test_realnum_expr expr-1.231\
{i1=-9223372036854775807, i2=2} {i1-i2} -9.22337203685478e+18
test_expr expr-1.232\
test_realnum_expr expr-1.232\
{i1=-9223372036854775807, i2=100000} {i1-i2} -9.22337203685488e+18
test_expr expr-1.233\
test_realnum_expr expr-1.233\
{i1=-9223372036854775808, i2=0} {i1-i2} -9223372036854775808
test_expr expr-1.234\
test_realnum_expr expr-1.234\
{i1=-9223372036854775808, i2=1} {i1-i2} -9.22337203685478e+18
test_expr expr-1.235\
test_realnum_expr expr-1.235\
{i2=9223372036854775807, i1=-1} {i1-i2} -9223372036854775808
test_expr expr-1.236\
test_realnum_expr expr-1.236\
{i2=9223372036854775807, i1=-2} {i1-i2} -9.22337203685478e+18
test_expr expr-1.237\
test_realnum_expr expr-1.237\
{i2=9223372036854775807, i1=-100000} {i1-i2} -9.22337203685488e+18
test_expr expr-1.238\
test_realnum_expr expr-1.238\
{i2=9223372036854775807, i1=0} {i1-i2} -9223372036854775807
test_expr expr-1.239\
test_realnum_expr expr-1.239\
{i2=9223372036854775807, i1=-1} {i1-i2} -9223372036854775808
test_expr expr-1.250\
test_realnum_expr expr-1.250\
{i1=4294967296, i2=2147483648} {i1*i2} 9.22337203685478e+18
test_expr expr-1.251\
test_realnum_expr expr-1.251\
{i1=4294967296, i2=2147483647} {i1*i2} 9223372032559808512
test_expr expr-1.252\
test_realnum_expr expr-1.252\
{i1=-4294967296, i2=2147483648} {i1*i2} -9223372036854775808
test_expr expr-1.253\
test_realnum_expr expr-1.253\
{i1=-4294967296, i2=2147483647} {i1*i2} -9223372032559808512
test_expr expr-1.254\
test_realnum_expr expr-1.254\
{i1=4294967296, i2=-2147483648} {i1*i2} -9223372036854775808
test_expr expr-1.255\
test_realnum_expr expr-1.255\
{i1=4294967296, i2=-2147483647} {i1*i2} -9223372032559808512
test_expr expr-1.256\
test_realnum_expr expr-1.256\
{i1=-4294967296, i2=-2147483648} {i1*i2} 9.22337203685478e+18
test_expr expr-1.257\
test_realnum_expr expr-1.257\
{i1=-4294967296, i2=-2147483647} {i1*i2} 9223372032559808512
}}
@@ -883,7 +888,7 @@ do_test expr-12.2 {
} {1 {near ")": syntax error}}
ifcapable floatingpoint {
do_test expr-13.1 {
do_realnum_test expr-13.1 {
execsql {
SELECT 12345678901234567890;
}
@@ -908,12 +913,12 @@ if {[working_64bit_int]} {
# If the value is too large, use String->Float conversion.
#
ifcapable floatingpoint {
do_test expr-13.4 {
do_realnum_test expr-13.4 {
execsql {
SELECT 0+'9223372036854775808'
}
} {9.22337203685478e+18}
do_test expr-13.5 {
do_realnum_test expr-13.5 {
execsql {
SELECT '9223372036854775808'+0
}
@@ -923,12 +928,12 @@ ifcapable floatingpoint {
# Use String->float conversion if the value is explicitly a floating
# point value.
#
do_test expr-13.6 {
do_realnum_test expr-13.6 {
execsql {
SELECT 0+'9223372036854775807.0'
}
} {9.22337203685478e+18}
do_test expr-13.7 {
do_realnum_test expr-13.7 {
execsql {
SELECT '9223372036854775807.0'+0
}
+106
View File
@@ -21,6 +21,8 @@ ifcapable {!foreignkey||!trigger} {
return
}
set testprefix fkey3
# Create a table and some data to work with.
#
do_test fkey3-1.1 {
@@ -77,4 +79,108 @@ do_test fkey3-2.1 {
}
} {1 100 1 101 2 100 2 101}
#-------------------------------------------------------------------------
# The following tests - fkey-3.* - test some edge cases to do with
# inserting rows into tables that have foreign keys where the parent
# table is the same as the child table. Especially cases where the
# new row being inserted matches itself.
#
do_execsql_test 3.1.1 {
CREATE TABLE t3(a, b, c, d,
UNIQUE(a, b),
FOREIGN KEY(c, d) REFERENCES t3(a, b)
);
INSERT INTO t3 VALUES(1, 2, 1, 2);
} {}
do_catchsql_test 3.1.2 {
INSERT INTO t3 VALUES(NULL, 2, 5, 2);
} {1 {foreign key constraint failed}}
do_catchsql_test 3.1.3 {
INSERT INTO t3 VALUES(NULL, 3, 5, 2);
} {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}}
do_execsql_test 3.3.1 {
CREATE TABLE t5(a INTEGER PRIMARY KEY, b REFERENCES t5(a));
INSERT INTO t5 VALUES(NULL, 1);
} {}
do_catchsql_test 3.3.2 {
INSERT INTO t5 VALUES(NULL, 3);
} {1 {foreign key constraint failed}}
do_execsql_test 3.4.1 {
CREATE TABLE t6(a INTEGER PRIMARY KEY, b, c, d,
FOREIGN KEY(c, d) REFERENCES t6(a, b)
);
CREATE UNIQUE INDEX t6i ON t6(b, a);
}
do_execsql_test 3.4.2 { INSERT INTO t6 VALUES(NULL, 'a', 1, 'a'); } {}
do_execsql_test 3.4.3 { INSERT INTO t6 VALUES(2, 'a', 2, 'a'); } {}
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}}
do_execsql_test 3.4.7 {
INSERT INTO t6 VALUES(100, 'one', 100, 'one');
DELETE FROM t6 WHERE a = 100;
}
do_execsql_test 3.4.8 {
INSERT INTO t6 VALUES(100, 'one', 100, 'one');
UPDATE t6 SET c = 1, d = 'a' WHERE a = 100;
DELETE FROM t6 WHERE a = 100;
}
do_execsql_test 3.5.1 {
CREATE TABLE t7(a, b, c, d INTEGER PRIMARY KEY,
FOREIGN KEY(c, d) REFERENCES t7(a, b)
);
CREATE UNIQUE INDEX t7i ON t7(a, b);
}
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}}
do_catchsql_test 3.5.5 {
INSERT INTO t7 VALUES('x', 450, 'x', 451);
} {1 {foreign key constraint failed}}
do_execsql_test 3.6.1 {
CREATE TABLE t8(a, b, c, d, e, FOREIGN KEY(c, d) REFERENCES t8(a, b));
CREATE UNIQUE INDEX t8i1 ON t8(a, b);
CREATE UNIQUE INDEX t8i2 ON t8(c);
INSERT INTO t8 VALUES(1, 1, 1, 1, 1);
}
do_catchsql_test 3.6.2 {
UPDATE t8 SET d = 2;
} {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; }
do_catchsql_test 3.6.5 {
CREATE TABLE TestTable (
id INTEGER PRIMARY KEY,
name text,
source_id integer not null,
parent_id integer,
foreign key(source_id, parent_id) references TestTable(source_id, id)
);
CREATE UNIQUE INDEX testindex on TestTable(source_id, id);
PRAGMA foreign_keys=1;
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}}
finish_test
+13
View File
@@ -24,6 +24,8 @@ ifcapable !fts3 {
return
}
set ::testprefix fts3token
proc escape_string {str} {
set out ""
foreach char [split $str ""] {
@@ -165,10 +167,21 @@ ifcapable icu {
do_icu_test fts3token-4.6 MiddleOfTheOcean $input $output
do_icu_test fts3token-4.7 th_TH $input $output
do_icu_test fts3token-4.8 en_US $input $output
do_execsql_test 5.1 {
CREATE VIRTUAL TABLE x1 USING fts3(name,TOKENIZE icu en_US);
insert into x1 (name) values (NULL);
insert into x1 (name) values (NULL);
delete from x1;
}
}
do_test fts3token-internal {
execsql { SELECT fts3_tokenizer_internal_test() }
} {ok}
finish_test
+658
View File
@@ -0,0 +1,658 @@
# 2011 June 10
#
# 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
# If this build does not include FTS3, skip the tests in this file.
#
ifcapable !fts3 { finish_test ; return }
source $testdir/fts3_common.tcl
source $testdir/malloc_common.tcl
set testprefix fts3auto
set sfep $sqlite_fts3_enable_parentheses
set sqlite_fts3_enable_parentheses 1
#--------------------------------------------------------------------------
# Start of Tcl infrastructure used by tests. The entry points are:
#
# do_fts3query_test
# fts3_make_deferrable
# fts3_zero_long_segments
#
#
# do_fts3query_test TESTNAME ?OPTIONS? TABLE MATCHEXPR
#
# This proc runs several test cases on FTS3/4 table $TABLE using match
# expression $MATCHEXPR. All documents in $TABLE must be formatted so that
# they can be "tokenized" using the Tcl list commands (llength, lindex etc.).
# The name and column names used by $TABLE must not require any quoting or
# escaping when used in SQL statements.
#
# $MATCHINFO may be any expression accepted by the FTS4 MATCH operator,
# except that the "<column-name>:token" syntax is not supported. Tcl list
# commands are used to tokenize the expression. Any parenthesis must appear
# either as separate list elements, or as the first (for opening) or last
# (for closing) character of a list element. i.e. the expression "(a OR b)c"
# will not be parsed correctly, but "( a OR b) c" will.
#
# Available OPTIONS are:
#
# -deferred TOKENLIST
#
# If the "deferred" option is supplied, it is passed a list of tokens that
# are deferred by FTS and result in the relevant matchinfo() stats being an
# approximation.
#
set sqlite_fts3_enable_parentheses 1
proc do_fts3query_test {tn args} {
set nArg [llength $args]
if {$nArg < 2 || ($nArg % 2)} {
set cmd do_fts3query_test
error "wrong # args: should be \"$cmd ?-deferred LIST? TABLE MATCHEXPR\""
}
set tbl [lindex $args [expr $nArg-2]]
set match [lindex $args [expr $nArg-1]]
set deferred [list]
foreach {k v} [lrange $args 0 [expr $nArg-3]] {
switch -- $k {
-deferred {
set deferred $v
}
default {
error "bad option \"$k\": must be -deferred"
}
}
}
get_near_results $tbl $match $deferred aMatchinfo
set matchinfo_asc [list]
foreach docid [lsort -integer -incr [array names aMatchinfo]] {
lappend matchinfo_asc $docid $aMatchinfo($docid)
}
set matchinfo_desc [list]
foreach docid [lsort -integer -decr [array names aMatchinfo]] {
lappend matchinfo_desc $docid $aMatchinfo($docid)
}
set title "(\"$match\" -> [llength [array names aMatchinfo]] rows)"
do_execsql_test $tn$title.1 "
SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid ASC
" [lsort -integer -incr [array names aMatchinfo]]
do_execsql_test $tn$title.2 "
SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid DESC
" [lsort -integer -decr [array names aMatchinfo]]
do_execsql_test $tn$title.3 "
SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl
WHERE $tbl MATCH '$match' ORDER BY docid DESC
" $matchinfo_desc
do_execsql_test $tn$title.4 "
SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl
WHERE $tbl MATCH '$match' ORDER BY docid ASC
" $matchinfo_asc
}
# fts3_make_deferrable TABLE TOKEN
#
proc fts3_make_deferrable {tbl token} {
set stmt [sqlite3_prepare db "SELECT * FROM $tbl" -1 dummy]
set name [sqlite3_column_name $stmt 0]
sqlite3_finalize $stmt
set nRow [db one "SELECT count(*) FROM $tbl"]
set pgsz [db one "PRAGMA page_size"]
execsql BEGIN
for {set i 0} {$i < ($nRow * $pgsz * 1.2)/100} {incr i} {
set doc [string repeat "$token " 100]
execsql "INSERT INTO $tbl ($name) VALUES(\$doc)"
}
execsql "INSERT INTO $tbl ($name) VALUES('aaaaaaa ${token}aaaaa')"
execsql COMMIT
return [expr $nRow*$pgsz]
}
# fts3_zero_long_segments TABLE ?LIMIT?
#
proc fts3_zero_long_segments {tbl limit} {
execsql "
UPDATE ${tbl}_segments
SET block = zeroblob(length(block))
WHERE length(block)>$limit
"
return [db changes]
}
proc mit {blob} {
set scan(littleEndian) i*
set scan(bigEndian) I*
binary scan $blob $scan($::tcl_platform(byteOrder)) r
return $r
}
db func mit mit
proc fix_phrase_expr {cols expr colfiltervar} {
upvar $colfiltervar iColFilter
set out [list]
foreach t $expr {
if {[string match *:* $t]} {
set col [lindex [split $t :] 0]
set t [lindex [split $t :] 1]
set iCol [lsearch $cols $col]
if {$iCol<0} { error "unknown column: $col" }
if {$iColFilter < 0} {
set iColFilter $iCol
} elseif {$iColFilter != $iCol} {
set iColFilter [llength $cols]
}
}
lappend out $t
}
return $out
}
proc fix_near_expr {cols expr colfiltervar} {
upvar $colfiltervar iColFilter
set iColFilter -1
set out [list]
lappend out [fix_phrase_expr $cols [lindex $expr 0] iColFilter]
foreach {a b} [lrange $expr 1 end] {
if {[string match -nocase near $a]} { set a 10 }
if {[string match -nocase near/* $a]} { set a [string range $a 5 end] }
lappend out $a
lappend out [fix_phrase_expr $cols $b iColFilter]
}
return $out
}
proc get_single_near_results {tbl expr deferred arrayvar nullvar} {
upvar $arrayvar aMatchinfo
upvar $nullvar nullentry
catch {array unset aMatchinfo}
set cols [list]
set miss [list]
db eval "PRAGMA table_info($tbl)" A { lappend cols $A(name) ; lappend miss 0 }
set expr [fix_near_expr $cols $expr iColFilter]
# Calculate the expected results using [fts3_near_match]. The following
# loop populates the "hits" and "counts" arrays as follows:
#
# 1. For each document in the table that matches the NEAR expression,
# hits($docid) is set to 1. The set of docids that match the expression
# can therefore be found using [array names hits].
#
# 2. For each column of each document in the table, counts($docid,$iCol)
# is set to the -phrasecountvar output.
#
set res [list]
catch { array unset hits }
db eval "SELECT docid, * FROM $tbl" d {
set iCol 0
foreach col [lrange $d(*) 1 end] {
set docid $d(docid)
if {$iColFilter<0 || $iCol==$iColFilter} {
set hit [fts3_near_match $d($col) $expr -p counts($docid,$iCol)]
if {$hit} { set hits($docid) 1 }
} else {
set counts($docid,$iCol) $miss
}
incr iCol
}
}
set nPhrase [expr ([llength $expr]+1)/2]
set nCol $iCol
# This block populates the nHit and nDoc arrays. For each phrase/column
# in the query/table, array elements are set as follows:
#
# nHit($iPhrase,$iCol) - Total number of hits for phrase $iPhrase in
# column $iCol.
#
# nDoc($iPhrase,$iCol) - Number of documents with at least one hit for
# phrase $iPhrase in column $iCol.
#
for {set iPhrase 0} {$iPhrase < $nPhrase} {incr iPhrase} {
for {set iCol 0} {$iCol < $nCol} {incr iCol} {
set nHit($iPhrase,$iCol) 0
set nDoc($iPhrase,$iCol) 0
}
}
foreach key [array names counts] {
set iCol [lindex [split $key ,] 1]
set iPhrase 0
foreach c $counts($key) {
if {$c>0} { incr nDoc($iPhrase,$iCol) 1 }
incr nHit($iPhrase,$iCol) $c
incr iPhrase
}
}
if {[llength $deferred] && [llength $expr]==1} {
set phrase [lindex $expr 0]
set rewritten [list]
set partial 0
foreach tok $phrase {
if {[lsearch $deferred $tok]>=0} {
lappend rewritten *
} else {
lappend rewritten $tok
set partial 1
}
}
if {$partial==0} {
set tblsize [db one "SELECT count(*) FROM $tbl"]
for {set iCol 0} {$iCol < $nCol} {incr iCol} {
set nHit(0,$iCol) $tblsize
set nDoc(0,$iCol) $tblsize
}
} elseif {$rewritten != $phrase} {
while {[lindex $rewritten end] == "*"} {
set rewritten [lrange $rewritten 0 end-1]
}
while {[lindex $rewritten 0] == "*"} {
set rewritten [lrange $rewritten 1 end]
}
get_single_near_results $tbl [list $rewritten] {} aRewrite nullentry
foreach docid [array names hits] {
set aMatchinfo($docid) $aRewrite($docid)
}
return
}
}
# Set up the aMatchinfo array. For each document, set aMatchinfo($docid) to
# contain the output of matchinfo('x') for the document.
#
foreach docid [array names hits] {
set mi [list]
for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
for {set iCol 0} {$iCol<$nCol} {incr iCol} {
lappend mi [lindex $counts($docid,$iCol) $iPhrase]
lappend mi $nHit($iPhrase,$iCol)
lappend mi $nDoc($iPhrase,$iCol)
}
}
set aMatchinfo($docid) $mi
}
# Set up the nullentry output.
#
set nullentry [list]
for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
for {set iCol 0} {$iCol<$nCol} {incr iCol} {
lappend nullentry 0 $nHit($iPhrase,$iCol) $nDoc($iPhrase,$iCol)
}
}
}
proc matching_brackets {expr} {
if {[string range $expr 0 0]!="(" || [string range $expr end end] !=")"} {
return 0
}
set iBracket 1
set nExpr [string length $expr]
for {set i 1} {$iBracket && $i < $nExpr} {incr i} {
set c [string range $expr $i $i]
if {$c == "("} {incr iBracket}
if {$c == ")"} {incr iBracket -1}
}
return [expr ($iBracket==0 && $i==$nExpr)]
}
proc get_near_results {tbl expr deferred arrayvar {nullvar ""}} {
upvar $arrayvar aMatchinfo
if {$nullvar != ""} { upvar $nullvar nullentry }
set expr [string trim $expr]
while { [matching_brackets $expr] } {
set expr [string trim [string range $expr 1 end-1]]
}
set prec(NOT) 1
set prec(AND) 2
set prec(OR) 3
set currentprec 0
set iBracket 0
set expr_length [llength $expr]
for {set i 0} {$i < $expr_length} {incr i} {
set op [lindex $expr $i]
if {$iBracket==0 && [info exists prec($op)] && $prec($op)>=$currentprec } {
set opidx $i
set currentprec $prec($op)
} else {
for {set j 0} {$j < [string length $op]} {incr j} {
set c [string range $op $j $j]
if {$c == "("} { incr iBracket +1 }
if {$c == ")"} { incr iBracket -1 }
}
}
}
if {$iBracket!=0} { error "mismatched brackets in: $expr" }
if {[info exists opidx]==0} {
get_single_near_results $tbl $expr $deferred aMatchinfo nullentry
} else {
set eLeft [lrange $expr 0 [expr $opidx-1]]
set eRight [lrange $expr [expr $opidx+1] end]
get_near_results $tbl $eLeft $deferred aLeft nullleft
get_near_results $tbl $eRight $deferred aRight nullright
switch -- [lindex $expr $opidx] {
"NOT" {
foreach hit [array names aLeft] {
if {0==[info exists aRight($hit)]} {
set aMatchinfo($hit) $aLeft($hit)
}
}
set nullentry $nullleft
}
"AND" {
foreach hit [array names aLeft] {
if {[info exists aRight($hit)]} {
set aMatchinfo($hit) [concat $aLeft($hit) $aRight($hit)]
}
}
set nullentry [concat $nullleft $nullright]
}
"OR" {
foreach hit [array names aLeft] {
if {[info exists aRight($hit)]} {
set aMatchinfo($hit) [concat $aLeft($hit) $aRight($hit)]
unset aRight($hit)
} else {
set aMatchinfo($hit) [concat $aLeft($hit) $nullright]
}
}
foreach hit [array names aRight] {
set aMatchinfo($hit) [concat $nullleft $aRight($hit)]
}
set nullentry [concat $nullleft $nullright]
}
}
}
}
# End of test procs. Actual tests are below this line.
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# The following test cases - fts3auto-1.* - focus on testing the Tcl
# command [fts3_near_match], which is used by other tests in this file.
#
proc test_fts3_near_match {tn doc expr res} {
fts3_near_match $doc $expr -phrasecountvar p
uplevel do_test [list $tn] [list [list set {} $p]] [list $res]
}
test_fts3_near_match 1.1.1 {a b c a b} a {2}
test_fts3_near_match 1.1.2 {a b c a b} {a 5 b 6 c} {2 2 1}
test_fts3_near_match 1.1.3 {a b c a b} {"a b"} {2}
test_fts3_near_match 1.1.4 {a b c a b} {"b c"} {1}
test_fts3_near_match 1.1.5 {a b c a b} {"c c"} {0}
test_fts3_near_match 1.2.1 "a b c d e f g" {b 2 f} {0 0}
test_fts3_near_match 1.2.2 "a b c d e f g" {b 3 f} {1 1}
test_fts3_near_match 1.2.3 "a b c d e f g" {f 2 b} {0 0}
test_fts3_near_match 1.2.4 "a b c d e f g" {f 3 b} {1 1}
test_fts3_near_match 1.2.5 "a b c d e f g" {"a b" 2 "f g"} {0 0}
test_fts3_near_match 1.2.6 "a b c d e f g" {"a b" 3 "f g"} {1 1}
set A "a b c d e f g h i j k l m n o p q r s t u v w x y z"
test_fts3_near_match 1.3.1 $A {"c d" 5 "i j" 1 "e f"} {0 0 0}
test_fts3_near_match 1.3.2 $A {"c d" 5 "i j" 2 "e f"} {1 1 1}
#--------------------------------------------------------------------------
# Test cases fts3auto-2.* run some simple tests using the
# [do_fts3query_test] proc.
#
foreach {tn create} {
1 "fts4(a, b)"
2 "fts4(a, b, order=DESC)"
3 "fts4(a, b, order=ASC)"
4 "fts4(a, b, prefix=1)"
5 "fts4(a, b, order=DESC, prefix=1)"
6 "fts4(a, b, order=ASC, prefix=1)"
} {
do_test 2.$tn.1 {
catchsql { DROP TABLE t1 }
execsql "CREATE VIRTUAL TABLE t1 USING $create"
for {set i 0} {$i<32} {incr i} {
set doc [list]
if {$i&0x01} {lappend doc one}
if {$i&0x02} {lappend doc two}
if {$i&0x04} {lappend doc three}
if {$i&0x08} {lappend doc four}
if {$i&0x10} {lappend doc five}
execsql { INSERT INTO t1 VALUES($doc, null) }
}
} {}
foreach {tn2 expr} {
1 {one}
2 {one NEAR/1 five}
3 {t*}
4 {t* NEAR/0 five}
5 {o* NEAR/1 f*}
6 {one NEAR five NEAR two NEAR four NEAR three}
7 {one NEAR xyz}
8 {one OR two}
9 {one AND two}
10 {one NOT two}
11 {one AND two OR three}
12 {three OR one AND two}
13 {(three OR one) AND two}
14 {(three OR one) AND two NOT (five NOT four)}
15 {"one two"}
16 {"one two" NOT "three four"}
} {
do_fts3query_test 2.$tn.2.$tn2 t1 $expr
}
}
#--------------------------------------------------------------------------
# Some test cases involving deferred tokens.
#
foreach {tn create} {
1 "fts4(x)"
2 "fts4(x, order=DESC)"
} {
catchsql { DROP TABLE t1 }
execsql "CREATE VIRTUAL TABLE t1 USING $create"
do_execsql_test 3.$tn.1 {
INSERT INTO t1(docid, x) VALUES(-2, 'a b c d e f g h i j k');
INSERT INTO t1(docid, x) VALUES(-1, 'b c d e f g h i j k a');
INSERT INTO t1(docid, x) VALUES(0, 'c d e f g h i j k a b');
INSERT INTO t1(docid, x) VALUES(1, 'd e f g h i j k a b c');
INSERT INTO t1(docid, x) VALUES(2, 'e f g h i j k a b c d');
INSERT INTO t1(docid, x) VALUES(3, 'f g h i j k a b c d e');
INSERT INTO t1(docid, x) VALUES(4, 'a c e g i k');
INSERT INTO t1(docid, x) VALUES(5, 'a d g j');
INSERT INTO t1(docid, x) VALUES(6, 'c a b');
}
set limit [fts3_make_deferrable t1 c]
do_fts3query_test 3.$tn.2.1 t1 {a OR c}
do_test 3.$tn.3 {
fts3_zero_long_segments t1 $limit
} {1}
foreach {tn2 expr def} {
1 {a NEAR c} {}
2 {a AND c} c
3 {"a c"} c
4 {"c a"} c
5 {"a c" NEAR/1 g} {}
6 {"a c" NEAR/0 g} {}
} {
do_fts3query_test 3.$tn.4.$tn2 -deferred $def t1 $expr
}
}
#--------------------------------------------------------------------------
#
foreach {tn create} {
1 "fts4(x, y)"
2 "fts4(x, y, order=DESC)"
3 "fts4(x, y, order=DESC, prefix=2)"
} {
execsql [subst {
DROP TABLE t1;
CREATE VIRTUAL TABLE t1 USING $create;
INSERT INTO t1 VALUES('one two five four five', '');
INSERT INTO t1 VALUES('', 'one two five four five');
INSERT INTO t1 VALUES('one two', 'five four five');
}]
do_fts3query_test 4.$tn.1.1 t1 {one AND five}
do_fts3query_test 4.$tn.1.2 t1 {one NEAR five}
do_fts3query_test 4.$tn.1.3 t1 {one NEAR/1 five}
do_fts3query_test 4.$tn.1.4 t1 {one NEAR/2 five}
do_fts3query_test 4.$tn.1.5 t1 {one NEAR/3 five}
do_test 4.$tn.2 {
set limit [fts3_make_deferrable t1 five]
execsql { INSERT INTO t1(t1) VALUES('optimize') }
expr {[fts3_zero_long_segments t1 $limit]>0}
} {1}
do_fts3query_test 4.$tn.3.1 -deferred five t1 {one AND five}
do_fts3query_test 4.$tn.3.2 -deferred five t1 {one NEAR five}
do_fts3query_test 4.$tn.3.3 -deferred five t1 {one NEAR/1 five}
do_fts3query_test 4.$tn.3.4 -deferred five t1 {one NEAR/2 five}
do_fts3query_test 4.$tn.3.5 -deferred five t1 {one NEAR/3 five}
do_fts3query_test 4.$tn.4.1 -deferred fi* t1 {on* AND fi*}
do_fts3query_test 4.$tn.4.2 -deferred fi* t1 {on* NEAR fi*}
do_fts3query_test 4.$tn.4.3 -deferred fi* t1 {on* NEAR/1 fi*}
do_fts3query_test 4.$tn.4.4 -deferred fi* t1 {on* NEAR/2 fi*}
do_fts3query_test 4.$tn.4.5 -deferred fi* t1 {on* NEAR/3 fi*}
}
#--------------------------------------------------------------------------
# The following test cases - fts3auto-5.* - focus on using prefix indexes.
#
set chunkconfig [fts3_configure_incr_load 1 1]
foreach {tn create pending} {
1 "fts4(a, b)" 1
2 "fts4(a, b, order=ASC, prefix=1)" 1
3 "fts4(a, b, order=ASC, prefix=1,3)" 0
4 "fts4(a, b, order=DESC, prefix=2,4)" 0
5 "fts4(a, b, order=DESC, prefix=1)" 0
6 "fts4(a, b, order=ASC, prefix=1,3)" 0
} {
execsql [subst {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING $create;
}]
if {$pending} {execsql BEGIN}
foreach {a b} {
"the song of songs which is solomons"
"let him kiss me with the kisses of his mouth for thy love is better than wine"
"because of the savour of thy good ointments thy name is as ointment poured forth therefore do the virgins love thee"
"draw me we will run after thee the king hath brought me into his chambers we will be glad and rejoice in thee we will remember thy love more than wine the upright love thee"
"i am black but comely o ye daughters of jerusalem as the tents of kedar as the curtains of solomon"
"look not upon me because i am black because the sun hath looked upon me my mothers children were angry with me they made me the keeper of the vineyards but mine own vineyard have i not kept"
"tell me o thou whom my soul loveth where thou feedest where thou makest thy flock to rest at noon for why should i be as one that turneth aside by the flocks of thy companions?"
"if thou know not o thou fairest among women go thy way forth by the footsteps of the flock and feed thy kids beside the shepherds tents"
"i have compared thee o my love to a company of horses in pharaohs chariots"
"thy cheeks are comely with rows of jewels thy neck with chains of gold"
"we will make thee borders of gold with studs of silver"
"while the king sitteth at his table my spikenard sendeth forth the smell thereof"
"a bundle of myrrh is my wellbeloved unto me he shall lie all night betwixt my breasts"
"my beloved is unto me as a cluster of camphire in the vineyards of en gedi"
"behold thou art fair my love behold thou art fair thou hast doves eyes"
"behold thou art fair my beloved yea pleasant also our bed is green"
"the beams of our house are cedar and our rafters of fir"
} {
execsql {INSERT INTO t1(a, b) VALUES($a, $b)}
}
do_fts3query_test 5.$tn.1.1 t1 {s*}
do_fts3query_test 5.$tn.1.2 t1 {so*}
do_fts3query_test 5.$tn.1.3 t1 {"s* o*"}
do_fts3query_test 5.$tn.1.4 t1 {b* NEAR/3 a*}
do_fts3query_test 5.$tn.1.5 t1 {a*}
do_fts3query_test 5.$tn.1.6 t1 {th* NEAR/5 a* NEAR/5 w*}
do_fts3query_test 5.$tn.1.7 t1 {"b* th* art* fair*"}
if {$pending} {execsql COMMIT}
}
eval fts3_configure_incr_load $chunkconfig
foreach {tn pending create} {
1 0 "fts4(a, b, c, d)"
2 1 "fts4(a, b, c, d)"
3 0 "fts4(a, b, c, d, order=DESC)"
4 1 "fts4(a, b, c, d, order=DESC)"
} {
execsql [subst {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING $create;
}]
if {$pending} { execsql BEGIN }
foreach {a b c d} {
"A B C" "D E F" "G H I" "J K L"
"B C D" "E F G" "H I J" "K L A"
"C D E" "F G H" "I J K" "L A B"
"D E F" "G H I" "J K L" "A B C"
"E F G" "H I J" "K L A" "B C D"
"F G H" "I J K" "L A B" "C D E"
} {
execsql { INSERT INTO t1 VALUES($a, $b, $c, $d) }
}
do_fts3query_test 6.$tn.1 t1 {b:G}
do_fts3query_test 6.$tn.2 t1 {b:G AND c:I}
do_fts3query_test 6.$tn.3 t1 {b:G NEAR c:I}
do_fts3query_test 6.$tn.4 t1 {a:C OR b:G OR c:K OR d:C}
do_fts3query_test 6.$tn.5 t1 {a:G OR b:G}
catchsql { COMMIT }
}
set sqlite_fts3_enable_parentheses $sfep
finish_test
+3 -3
View File
@@ -38,10 +38,10 @@ do_execsql_test 1.2 {
six 1 1 three 4 6 two 1 1
}
do_execsql_test 1.3 {
DELETE FROM t1;
do_execsql_test 1.3.1 { DELETE FROM t1; }
do_execsql_test 1.3.2 {
SELECT term, documents, occurrences FROM terms WHERE col = '*';
} {}
}
do_execsql_test 1.4 {
INSERT INTO t1 VALUES('a b a b a b a');
+139
View File
@@ -0,0 +1,139 @@
# 2011 April 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 script is testing the FTS3 module.
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix fts3conf
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
finish_test
return
}
proc fts3_integrity {tn db tbl} {
if {[sqlite3_get_autocommit $db]==0} {
error "fts3_integrity does not work with an open transaction"
}
set sql [db one {SELECT sql FROM sqlite_master WHERE name = $tbl}]
regexp -nocase {[^(]* using (.*)} $sql -> tail
set cols [list]
$db eval "PRAGMA table_info($tbl)" {
lappend cols $name
}
set cols [join [concat docid $cols] ,]
$db eval [subst {
CREATE VIRTUAL TABLE fts3check USING fts4term($tbl);
CREATE VIRTUAL TABLE temp.fts3check2 USING $tail;
INSERT INTO temp.fts3check2($cols) SELECT docid, * FROM $tbl;
CREATE VIRTUAL TABLE temp.fts3check3 USING fts4term(fts3check2);
}]
set m1 [$db one {SELECT md5sum(term, docid, col, pos) FROM fts3check}]
set m2 [$db one {SELECT md5sum(term, docid, col, pos) FROM fts3check3}]
$db eval {
DROP TABLE fts3check;
DROP TABLE temp.fts3check2;
DROP TABLE temp.fts3check3;
}
uplevel [list do_test $tn [list set {} $m1] $m2]
}
do_execsql_test 1.0.1 {
CREATE VIRTUAL TABLE t1 USING fts3(x);
INSERT INTO t1(rowid, x) VALUES(1, 'a b c d');
INSERT INTO t1(rowid, x) VALUES(2, 'e f g h');
CREATE TABLE source(a, b);
INSERT INTO source VALUES(4, 'z');
INSERT INTO source VALUES(2, 'y');
}
db_save_and_close
set T1 "INTO t1(rowid, x) VALUES(1, 'x')"
set T2 "INTO t1(rowid, x) SELECT * FROM source"
set T3 "t1 SET docid = 2 WHERE docid = 1"
set T4 "t1 SET docid = CASE WHEN docid = 1 THEN 4 ELSE 3 END WHERE docid <=2"
foreach {tn sql uses constraint data} [subst {
1 "INSERT OR ROLLBACK $T1" 0 1 {{a b c d} {e f g h}}
2 "INSERT OR ABORT $T1" 0 1 {{a b c d} {e f g h} {i j k l}}
3 "INSERT OR FAIL $T1" 0 1 {{a b c d} {e f g h} {i j k l}}
4 "INSERT OR IGNORE $T1" 0 0 {{a b c d} {e f g h} {i j k l}}
5 "INSERT OR REPLACE $T1" 0 0 {x {e f g h} {i j k l}}
6 "INSERT OR ROLLBACK $T2" 1 1 {{a b c d} {e f g h}}
7 "INSERT OR ABORT $T2" 1 1 {{a b c d} {e f g h} {i j k l}}
8 "INSERT OR FAIL $T2" 1 1 {{a b c d} {e f g h} {i j k l} z}
9 "INSERT OR IGNORE $T2" 1 0 {{a b c d} {e f g h} {i j k l} z}
10 "INSERT OR REPLACE $T2" 1 0 {{a b c d} y {i j k l} z}
11 "UPDATE OR ROLLBACK $T3" 1 1 {{a b c d} {e f g h}}
12 "UPDATE OR ABORT $T3" 1 1 {{a b c d} {e f g h} {i j k l}}
13 "UPDATE OR FAIL $T3" 1 1 {{a b c d} {e f g h} {i j k l}}
14 "UPDATE OR IGNORE $T3" 1 0 {{a b c d} {e f g h} {i j k l}}
15 "UPDATE OR REPLACE $T3" 1 0 {{a b c d} {i j k l}}
16 "UPDATE OR ROLLBACK $T4" 1 1 {{a b c d} {e f g h}}
17 "UPDATE OR ABORT $T4" 1 1 {{a b c d} {e f g h} {i j k l}}
18 "UPDATE OR FAIL $T4" 1 1 {{e f g h} {i j k l} {a b c d}}
19 "UPDATE OR IGNORE $T4" 1 0 {{e f g h} {i j k l} {a b c d}}
20 "UPDATE OR REPLACE $T4" 1 0 {{e f g h} {a b c d}}
}] {
db_restore_and_reopen
execsql {
BEGIN;
INSERT INTO t1(rowid, x) VALUES(3, 'i j k l');
}
set R(0) {0 {}}
set R(1) {1 {constraint failed}}
do_catchsql_test 1.$tn.1 $sql $R($constraint)
do_catchsql_test 1.$tn.2 { SELECT * FROM t1 } [list 0 $data]
catchsql COMMIT
fts3_integrity 1.$tn.3 db t1
do_test 1.$tn.4 [list sql_uses_stmt db $sql] $uses
}
do_execsql_test 2.1.1 {
DELETE FROM t1;
BEGIN;
INSERT INTO t1 VALUES('a b c');
SAVEPOINT a;
INSERT INTO t1 VALUES('x y z');
ROLLBACK TO a;
COMMIT;
}
fts3_integrity 2.1.2 db t1
do_catchsql_test 2.2.1 {
DELETE FROM t1;
BEGIN;
INSERT INTO t1(docid, x) VALUES(0, 'a b c');
INSERT INTO t1(docid, x) VALUES(1, 'a b c');
REPLACE INTO t1(docid, x) VALUES('zero', 'd e f');
} {1 {datatype mismatch}}
do_execsql_test 2.2.2 { COMMIT }
do_execsql_test 2.2.3 { SELECT * FROM t1 } {{a b c} {a b c}}
fts3_integrity 2.2.4 db t1
finish_test
+7
View File
@@ -40,6 +40,7 @@ do_test fts3corrupt-1.2 {
do_catchsql_test 1.3 {
INSERT INTO t1 VALUES('world');
} {1 {database disk image is malformed}}
do_test 1.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB
do_execsql_test 1.4 {
DROP TABLE t1;
}
@@ -69,6 +70,7 @@ do_test fts3corrupt-2.1 {
do_catchsql_test 2.2 {
SELECT rowid FROM t1 WHERE t1 MATCH 'hello'
} {1 {database disk image is malformed}}
do_test 2.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB
do_execsql_test 3.0 {
DROP TABLE t1;
@@ -86,6 +88,7 @@ do_test fts3corrupt-3.1 {
do_catchsql_test 3.2 {
SELECT rowid FROM t1 WHERE t1 MATCH 'world'
} {1 {database disk image is malformed}}
do_test 3.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB
do_execsql_test 4.0 {
@@ -111,6 +114,7 @@ do_catchsql_test 4.2 {
UPDATE t1_segdir SET root = X'FFFFFFFFFFFFFFFF';
SELECT rowid FROM t1 WHERE t1 MATCH 'world';
} {1 {database disk image is malformed}}
do_test 4.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB
set blob [binary format cca*cca*cca*cca*cca*cca*cca*cca*cca*cca*a* \
22 120 [string repeat a 120] \
@@ -130,6 +134,7 @@ do_catchsql_test 4.3 {
UPDATE t1_segdir SET root = $blob;
SELECT rowid FROM t1 WHERE t1 MATCH 'world';
} {1 {database disk image is malformed}}
do_test 4.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB
# Test a special kind of corruption, where the %_stat table contains
# an invalid entry. At one point this could lead to a division-by-zero
@@ -152,10 +157,12 @@ do_catchsql_test 5.2 {
UPDATE t1_stat SET value = X'0000';
SELECT matchinfo(t1, 'nxa') FROM t1 WHERE t1 MATCH 't*';
} {1 {database disk image is malformed}}
do_test 5.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB
do_catchsql_test 5.3 {
UPDATE t1_stat SET value = NULL;
SELECT matchinfo(t1, 'nxa') FROM t1 WHERE t1 MATCH 't*';
} {1 {database disk image is malformed}}
do_test 5.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB
finish_test
+18 -11
View File
@@ -20,6 +20,8 @@ ifcapable !fts3 {
set sqlite_fts3_enable_parentheses 1
set fts3_simple_deferred_tokens_only 1
set ::testprefix fts3defer
#--------------------------------------------------------------------------
@@ -257,7 +259,6 @@ foreach {tn setup} {
do_select_test 1.2 {
SELECT rowid FROM t1 WHERE t1 MATCH 'jk eh'
} {100}
if {$tn==3} breakpoint
do_select_test 1.3 {
SELECT rowid FROM t1 WHERE t1 MATCH 'jk ubwrfqnbjf'
} {7 70 98}
@@ -282,13 +283,16 @@ if {$tn==3} breakpoint
do_select_test 1.10 {
SELECT rowid FROM t1 WHERE t1 MATCH 'z* vgsld'
} {10 13 17 31 35 51 58 88 89 90 93 100}
do_select_test 1.11 {
SELECT rowid FROM t1
WHERE t1 MATCH '(
zdu OR zexh OR zf OR zhbrzadb OR zidhxhbtv OR
zk OR zkhdvkw OR zm OR zsmhnf
) vgsld'
} {10 13 17 31 35 51 58 88 89 90 93 100}
if { $fts3_simple_deferred_tokens_only==0 } {
do_select_test 1.11 {
SELECT rowid FROM t1
WHERE t1 MATCH '(
zdu OR zexh OR zf OR zhbrzadb OR zidhxhbtv OR
zk OR zkhdvkw OR zm OR zsmhnf
) vgsld'
} {10 13 17 31 35 51 58 88 89 90 93 100}
}
do_select_test 2.1 {
SELECT rowid FROM t1 WHERE t1 MATCH '"zm agmckuiu"'
@@ -364,6 +368,7 @@ if {$tn==3} breakpoint
foreach DO_MALLOC_TEST $dmt_modes {
# Phrase search.
#
do_select_test 5.$DO_MALLOC_TEST.1 {
SELECT rowid FROM t1 WHERE t1 MATCH '"jk mjpavjuhw"'
} {8 15 36 64 67 72}
@@ -416,9 +421,11 @@ if {$tn==3} breakpoint
do_select_test 6.2.2 {
SELECT rowid FROM t1 WHERE t1 MATCH '"zm azavwm"'
} {15 26 92 96}
do_select_test 6.2.3 {
SELECT rowid FROM t1 WHERE t1 MATCH '"jk xduvfhk" OR "zm azavwm"'
} {8 15 26 92 96}
if {$fts3_simple_deferred_tokens_only==0} {
do_select_test 6.2.3 {
SELECT rowid FROM t1 WHERE t1 MATCH '"jk xduvfhk" OR "zm azavwm"'
} {8 15 26 92 96}
}
}
set testprefix fts3defer
+13 -3
View File
@@ -48,6 +48,10 @@ do_execsql_test 1.1.4 {
UPDATE t1_segments SET block = zeroblob(length(block)) WHERE length(block)>10000;
} {2}
do_execsql_test 1.2.0 {
SELECT content FROM t1 WHERE t1 MATCH 'f (e a)';
} {{a b c d e f a x y}}
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}}
@@ -58,7 +62,7 @@ do_execsql_test 1.2.2 {
} [list \
{a b c d [e] [f] [a] x y} \
{0 1 8 1 0 0 10 1 0 2 12 1} \
[list 3 1 1 1 1 1 8 8 1 8 8 8 5001 9]
[list 3 1 1 1 1 1 1 1 1 1 1 8 5001 9]
]
do_execsql_test 1.2.3 {
@@ -67,7 +71,7 @@ do_execsql_test 1.2.3 {
} [list \
{[a] b c d [e] [f] [a] x y} \
{0 2 0 1 0 1 8 1 0 0 10 1 0 2 12 1} \
[list 3 1 1 1 1 1 8 8 2 8 8 8 5001 9]
[list 3 1 1 1 1 1 1 1 2 2 1 8 5001 9]
]
do_execsql_test 1.3.1 { DROP TABLE t1 }
@@ -99,8 +103,14 @@ foreach {tn sql} {
[list 2 1 1 54 54 1 3 3 54 372 7] \
]
set sqlite_fts3_enable_parentheses 1
do_execsql_test 2.2.$tn.2 {
SELECT mit(matchinfo(t2, 'x')) FROM t2 WHERE t2 MATCH 'g z';
} [list \
[list 1 2 2 1 54 54] \
]
set sqlite_fts3_enable_parentheses 1
do_execsql_test 2.2.$tn.3 {
SELECT mit(matchinfo(t2, 'x')) FROM t2 WHERE t2 MATCH 'g OR (g z)';
} [list \
[list 1 2 2 1 2 2 1 54 54] \
+11 -3
View File
@@ -68,7 +68,11 @@ do_execsql_test 3.1 {
do_execsql_test 3.2 {
CREATE VIRTUAL TABLE xx USING FTS4;
}
do_execsql_test 3.3 {
SELECT * FROM xx WHERE xx MATCH 'abc';
}
do_execsql_test 3.4 {
SELECT * FROM xx WHERE xx MATCH 'a b c';
}
@@ -240,9 +244,13 @@ do_matchinfo_test 4.2.6 t5 {t5 MATCH 'a OR b'} { s {1 2 1} }
do_execsql_test 4.3.0 "INSERT INTO t5 VALUES('x y [string repeat {b } 50000]')";
do_matchinfo_test 4.3.1 t5 {t5 MATCH 'a a'} {
x {{5 8 2 5 5 5} {3 8 2 3 5 5}}
s {2 1}
# It used to be that the second 'a' token would be deferred. That doesn't
# work any longer.
if 0 {
do_matchinfo_test 4.3.1 t5 {t5 MATCH 'a a'} {
x {{5 8 2 5 5 5} {3 8 2 3 5 5}}
s {2 1}
}
}
do_matchinfo_test 4.3.2 t5 {t5 MATCH 'a b'} { s {2} }
+203
View File
@@ -0,0 +1,203 @@
# 2011 May 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. The
# focus of this script is testing the FTS3 module.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix fts3prefix
ifcapable !fts3 {
finish_test
return
}
# This proc tests that the prefixes index appears to represent the same content
# as the terms index.
#
proc fts3_terms_and_prefixes {db tbl prefixlengths} {
set iIndex 0
foreach len $prefixlengths {
incr iIndex
$db eval {
DROP TABLE IF EXISTS fts3check1;
DROP TABLE IF EXISTS fts3check2;
}
$db eval "CREATE VIRTUAL TABLE fts3check1 USING fts4term($tbl, 0);"
$db eval "CREATE VIRTUAL TABLE fts3check2 USING fts4term($tbl, $iIndex);"
$db eval {
DROP TABLE IF EXISTS temp.terms;
DROP TABLE IF EXISTS temp.prefixes;
CREATE TEMP TABLE terms AS SELECT * FROM fts3check1;
CREATE TEMP TABLE prefixes AS SELECT * FROM fts3check2;
CREATE INDEX temp.idx ON prefixes(term);
DROP TABLE fts3check1;
DROP TABLE fts3check2;
}
set nExpect 0
$db eval { SELECT term, docid, col, pos FROM temp.terms } a {
if {[string length $a(term)]<$len} continue
incr nExpect
set prefix [string range $a(term) 0 [expr $len-1]]
set r [$db one {
SELECT count(*) FROM temp.prefixes WHERE
term = $prefix AND docid = $a(docid) AND col = $a(col) AND pos = $a(pos)
}]
if {$r != 1} {
error "$t, $a(docid), $a(col), $a(pos)"
}
}
set nCount [$db one {SELECT count(*) FROM temp.prefixes}]
if {$nCount != $nExpect} {
error "prefixes.count(*) is $nCount expected $nExpect"
}
execsql { DROP TABLE temp.prefixes }
execsql { DROP TABLE temp.terms }
set list [list]
$db eval "
SELECT sum( 1 << (16*(level%1024)) ) AS total, (level/1024) AS tree
FROM ${tbl}_segdir GROUP BY tree
" {
lappend list [list $total $tree]
}
if { [lsort -integer -index 0 $list] != [lsort -integer -index 1 $list] } {
error "inconsistent tree structures: $list"
}
}
return ""
}
proc fts3_tap_test {tn db tbl lens} {
uplevel [list do_test $tn [list fts3_terms_and_prefixes $db $tbl $lens] ""]
}
#-------------------------------------------------------------------------
# Test cases 1.* are a sanity check. They test that the prefixes index is
# being constructed correctly for the simplest possible case.
#
do_execsql_test 1.1 {
CREATE VIRTUAL TABLE t1 USING fts4(prefix='1,3,6');
CREATE VIRTUAL TABLE p1 USING fts4term(t1, 1);
CREATE VIRTUAL TABLE p2 USING fts4term(t1, 2);
CREATE VIRTUAL TABLE p3 USING fts4term(t1, 3);
CREATE VIRTUAL TABLE terms USING fts4term(t1);
}
do_execsql_test 1.2 {
INSERT INTO t1 VALUES('sqlite mysql firebird');
}
do_execsql_test 1.3.1 { SELECT term FROM p1 } {f m s}
do_execsql_test 1.3.2 { SELECT term FROM p2 } {fir mys sql}
do_execsql_test 1.3.3 { SELECT term FROM p3 } {firebi sqlite}
do_execsql_test 1.4 {
SELECT term FROM terms;
} {firebird mysql sqlite}
fts3_tap_test 1.5 db t1 {1 3 6}
#-------------------------------------------------------------------------
# A slightly more complicated dataset. This test also verifies that DELETE
# operations do not corrupt the prefixes index.
#
do_execsql_test 2.1 {
INSERT INTO t1 VALUES('FTS3 and FTS4 are an SQLite virtual table modules');
INSERT INTO t1 VALUES('that allows users to perform full-text searches on');
INSERT INTO t1 VALUES('a set of documents. The most common (and');
INSERT INTO t1 VALUES('effective) way to describe full-text searches is');
INSERT INTO t1 VALUES('"what Google, Yahoo and Altavista do with');
INSERT INTO t1 VALUES('documents placed on the World Wide Web". Users');
INSERT INTO t1 VALUES('input a term, or series of terms, perhaps');
INSERT INTO t1 VALUES('connected by a binary operator or grouped together');
INSERT INTO t1 VALUES('into a phrase, and the full-text query system');
INSERT INTO t1 VALUES('finds the set of documents that best matches those');
INSERT INTO t1 VALUES('terms considering the operators and groupings the');
INSERT INTO t1 VALUES('user has specified. This article describes the');
INSERT INTO t1 VALUES('deployment and usage of FTS3 and FTS4.');
INSERT INTO t1 VALUES('FTS1 and FTS2 are obsolete full-text search');
INSERT INTO t1 VALUES('modules for SQLite. There are known issues with');
INSERT INTO t1 VALUES('these older modules and their use should be');
INSERT INTO t1 VALUES('avoided. Portions of the original FTS3 code were');
INSERT INTO t1 VALUES('contributed to the SQLite project by Scott Hess of');
INSERT INTO t1 VALUES('Google. It is now developed and maintained as part');
INSERT INTO t1 VALUES('of SQLite. ');
}
fts3_tap_test 2.2 db t1 {1 3 6}
do_execsql_test 2.3 { DELETE FROM t1 WHERE docid%2; }
fts3_tap_test 2.4 db t1 {1 3 6}
do_execsql_test 2.5 { INSERT INTO t1(t1) VALUES('optimize') }
fts3_tap_test 2.6 db t1 {1 3 6}
do_execsql_test 3.1 {
CREATE VIRTUAL TABLE t2 USING fts4(prefix='1,2,3');
INSERT INTO t2 VALUES('On 12 September the wind direction turned and');
INSERT INTO t2 VALUES('William''s fleet sailed. A storm blew up and the');
INSERT INTO t2 VALUES('fleet was forced to take shelter at');
INSERT INTO t2 VALUES('Saint-Valery-sur-Somme and again wait for the wind');
INSERT INTO t2 VALUES('to change. On 27 September the Norman fleet');
INSERT INTO t2 VALUES('finally set sail, landing in England at Pevensey');
INSERT INTO t2 VALUES('Bay (Sussex) on 28 September. William then moved');
INSERT INTO t2 VALUES('to Hastings, a few miles to the east, where he');
INSERT INTO t2 VALUES('built a prefabricated wooden castle for a base of');
INSERT INTO t2 VALUES('operations. From there, he ravaged the hinterland');
INSERT INTO t2 VALUES('and waited for Harold''s return from the north.');
INSERT INTO t2 VALUES('On 12 September the wind direction turned and');
INSERT INTO t2 VALUES('William''s fleet sailed. A storm blew up and the');
INSERT INTO t2 VALUES('fleet was forced to take shelter at');
INSERT INTO t2 VALUES('Saint-Valery-sur-Somme and again wait for the wind');
INSERT INTO t2 VALUES('to change. On 27 September the Norman fleet');
INSERT INTO t2 VALUES('finally set sail, landing in England at Pevensey');
INSERT INTO t2 VALUES('Bay (Sussex) on 28 September. William then moved');
INSERT INTO t2 VALUES('to Hastings, a few miles to the east, where he');
INSERT INTO t2 VALUES('built a prefabricated wooden castle for a base of');
INSERT INTO t2 VALUES('operations. From there, he ravaged the hinterland');
INSERT INTO t2 VALUES('and waited for Harold''s return from the north.');
}
fts3_tap_test 3.2 db t2 {1 2 3}
do_execsql_test 3.3 { SELECT optimize(t2) FROM t2 LIMIT 1 } {{Index optimized}}
fts3_tap_test 3.4 db t2 {1 2 3}
#-------------------------------------------------------------------------
# Simple tests for reading the prefix-index.
#
do_execsql_test 4.1 {
CREATE VIRTUAL TABLE t3 USING fts4(prefix="1,4");
INSERT INTO t3 VALUES('one two three');
INSERT INTO t3 VALUES('four five six');
INSERT INTO t3 VALUES('seven eight nine');
}
do_execsql_test 4.2 {
SELECT * FROM t3 WHERE t3 MATCH 'f*'
} {{four five six}}
do_execsql_test 4.3 {
SELECT * FROM t3 WHERE t3 MATCH 'four*'
} {{four five six}}
do_execsql_test 4.4 {
SELECT * FROM t3 WHERE t3 MATCH 's*'
} {{four five six} {seven eight nine}}
do_execsql_test 4.5 {
SELECT * FROM t3 WHERE t3 MATCH 'sev*'
} {{seven eight nine}}
do_execsql_test 4.6 {
SELECT * FROM t3 WHERE t3 MATCH 'one*'
} {{one two three}}
finish_test
+47 -21
View File
@@ -162,7 +162,7 @@ proc simple_phrase {zPrefix} {
# This [proc] is used to test the FTS3 matchinfo() function.
#
proc simple_token_matchinfo {zToken} {
proc simple_token_matchinfo {zToken bDesc} {
set nDoc(0) 0
set nDoc(1) 0
@@ -171,6 +171,8 @@ proc simple_token_matchinfo {zToken} {
set nHit(1) 0
set nHit(2) 0
set dir -inc
if {$bDesc} { set dir -dec }
foreach key [array names ::t1] {
set value $::t1($key)
@@ -184,7 +186,7 @@ proc simple_token_matchinfo {zToken} {
}
set ret [list]
foreach docid [lsort -integer [array names a]] {
foreach docid [lsort -integer $dir [array names a]] {
if { [lindex [lsort -integer $a($docid)] end] } {
set matchinfo [list 1 3]
foreach i {0 1 2} hit $a($docid) {
@@ -262,22 +264,37 @@ proc mit {blob} {
return $r
}
db func mit mit
set sqlite_fts3_enable_parentheses 1
foreach nodesize {50 500 1000 2000} {
proc do_orderbydocid_test {tn sql res} {
uplevel [list do_select_test $tn.asc "$sql ORDER BY docid ASC" $res]
uplevel [list do_select_test $tn.desc "$sql ORDER BY docid DESC" \
[lsort -int -dec $res]
]
}
set NUM_TRIALS 100
foreach {nodesize order} {
50 DESC
50 ASC
500 ASC
1000 DESC
2000 ASC
} {
catch { array unset ::t1 }
set testname "$nodesize/$order"
# Create the FTS3 table. Populate it (and the Tcl array) with 100 rows.
#
db transaction {
catchsql { DROP TABLE t1 }
execsql "CREATE VIRTUAL TABLE t1 USING fts3(a, b, c)"
execsql "CREATE VIRTUAL TABLE t1 USING fts4(a, b, c, order=$order)"
execsql "INSERT INTO t1(t1) VALUES('nodesize=$nodesize')"
for {set i 0} {$i < 100} {incr i} { insert_row $i }
}
for {set iTest 1} {$iTest <= 100} {incr iTest} {
for {set iTest 1} {$iTest <= $NUM_TRIALS} {incr iTest} {
catchsql COMMIT
set DO_MALLOC_TEST 0
@@ -286,6 +303,8 @@ foreach nodesize {50 500 1000 2000} {
set DO_MALLOC_TEST 1
set nRep 2
}
set ::testprefix fts3rnd-1.$testname.$iTest
# Delete one row, update one row and insert one row.
#
@@ -307,7 +326,7 @@ foreach nodesize {50 500 1000 2000} {
if {0==($iTest%2)} { execsql COMMIT }
if {0==($iTest%2)} {
do_test fts3rnd-1.$nodesize.$iTest.0 { fts3_integrity_check t1 } ok
#do_test 0 { fts3_integrity_check t1 } ok
}
# Pick 10 terms from the vocabulary. Check that the results of querying
@@ -317,9 +336,14 @@ foreach nodesize {50 500 1000 2000} {
#
for {set i 0} {$i < 10} {incr i} {
set term [random_term]
do_select_test fts3rnd-1.$nodesize.$iTest.1.$i {
do_select_test 1.$i.asc {
SELECT docid, mit(matchinfo(t1)) FROM t1 WHERE t1 MATCH $term
} [simple_token_matchinfo $term]
ORDER BY docid ASC
} [simple_token_matchinfo $term 0]
do_select_test 1.$i.desc {
SELECT docid, mit(matchinfo(t1)) FROM t1 WHERE t1 MATCH $term
ORDER BY docid DESC
} [simple_token_matchinfo $term 1]
}
# This time, use the first two characters of each term as a term prefix
@@ -329,7 +353,7 @@ foreach nodesize {50 500 1000 2000} {
for {set i 0} {$i < $nRep} {incr i} {
set prefix [string range [random_term] 0 end-1]
set match "${prefix}*"
do_select_test fts3rnd-1.$nodesize.$iTest.2.$i {
do_orderbydocid_test 2.$i {
SELECT docid FROM t1 WHERE t1 MATCH $match
} [simple_phrase $match]
}
@@ -339,7 +363,7 @@ foreach nodesize {50 500 1000 2000} {
for {set i 0} {$i < $nRep} {incr i} {
set term [list [random_term] [random_term]]
set match "\"$term\""
do_select_test fts3rnd-1.$nodesize.$iTest.3.$i {
do_orderbydocid_test 3.$i {
SELECT docid FROM t1 WHERE t1 MATCH $match
} [simple_phrase $term]
}
@@ -349,7 +373,7 @@ foreach nodesize {50 500 1000 2000} {
for {set i 0} {$i < $nRep} {incr i} {
set term [list [random_term] [random_term] [random_term]]
set match "\"$term\""
do_select_test fts3rnd-1.$nodesize.$iTest.4.$i {
do_orderbydocid_test 4.$i {
SELECT docid FROM t1 WHERE t1 MATCH $match
} [simple_phrase $term]
}
@@ -362,17 +386,19 @@ foreach nodesize {50 500 1000 2000} {
append query "[string range [random_term] 0 end-1]*"
set match "\"$query\""
do_select_test fts3rnd-1.$nodesize.$iTest.5.$i {
do_orderbydocid_test 5.$i {
SELECT docid FROM t1 WHERE t1 MATCH $match
} [simple_phrase $query]
}
# A NEAR query with terms as the arguments.
# A NEAR query with terms as the arguments:
#
# ... MATCH '$term1 NEAR $term2' ...
#
for {set i 0} {$i < $nRep} {incr i} {
set terms [list [random_term] [random_term]]
set match [join $terms " NEAR "]
do_select_test fts3rnd-1.$nodesize.$iTest.6.$i {
do_orderbydocid_test 6.$i {
SELECT docid FROM t1 WHERE t1 MATCH $match
} [simple_near $terms 10]
}
@@ -383,7 +409,7 @@ foreach nodesize {50 500 1000 2000} {
set terms [list [random_term] [random_term] [random_term]]
set nNear 11
set match [join $terms " NEAR/$nNear "]
do_select_test fts3rnd-1.$nodesize.$iTest.7.$i {
do_orderbydocid_test 7.$i {
SELECT docid FROM t1 WHERE t1 MATCH $match
} [simple_near $terms $nNear]
}
@@ -399,7 +425,7 @@ foreach nodesize {50 500 1000 2000} {
set term1 [random_term]
set term2 [random_term]
set match "$term1 $op $term2"
do_select_test fts3rnd-1.$nodesize.$iTest.$tn.$i {
do_orderbydocid_test $tn.$i {
SELECT docid FROM t1 WHERE t1 MATCH $match
} [$proc [simple_phrase $term1] [simple_phrase $term2]]
}
@@ -408,9 +434,9 @@ foreach nodesize {50 500 1000 2000} {
# Set operations on NEAR queries.
#
foreach {tn op proc} {
8 OR setop_or
9 NOT setop_not
10 AND setop_and
11 OR setop_or
12 NOT setop_not
13 AND setop_and
} {
for {set i 0} {$i < $nRep} {incr i} {
set term1 [random_term]
@@ -418,7 +444,7 @@ foreach nodesize {50 500 1000 2000} {
set term3 [random_term]
set term4 [random_term]
set match "$term1 NEAR $term2 $op $term3 NEAR $term4"
do_select_test fts3rnd-1.$nodesize.$iTest.$tn.$i {
do_orderbydocid_test $tn.$i {
SELECT docid FROM t1 WHERE t1 MATCH $match
} [$proc \
[simple_near [list $term1 $term2] 10] \
+162
View File
@@ -0,0 +1,162 @@
# 2011 May 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. The
# focus of this script is testing the FTS3 module.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
finish_test
return
}
proc build_database {nRow param} {
db close
forcedelete test.db
sqlite3 db test.db
set vocab [list aa ab ac ba bb bc ca cb cc da]
expr srand(0)
execsql "CREATE VIRTUAL TABLE t1 USING fts4($param)"
for {set i 0} {$i < $nRow} {incr i} {
set v [expr int(rand()*1000000)]
set doc [list]
for {set div 1} {$div < 1000000} {set div [expr $div*10]} {
lappend doc [lindex $vocab [expr ($v/$div) % 10]]
}
execsql { INSERT INTO t1 VALUES($doc) }
}
}
set testprefix fts3sort
unset -nocomplain CONTROL
foreach {t param} {
1 ""
2 "order=asc"
3 "order=desc"
} {
set testprefix fts3sort-1.$t
set nRow 1000
do_test 1.0 {
build_database $nRow $param
execsql { SELECT count(*) FROM t1 }
} $nRow
foreach {tn query} {
1 "SELECT docid, * FROM t1"
2 "SELECT docid, * FROM t1 WHERE t1 MATCH 'aa'"
3 "SELECT docid, * FROM t1 WHERE t1 MATCH 'a*'"
4 "SELECT docid, quote(matchinfo(t1)) FROM t1 WHERE t1 MATCH 'a*'"
5 "SELECT docid, quote(matchinfo(t1,'pcnxals')) FROM t1 WHERE t1 MATCH 'b*'"
6 "SELECT docid, * FROM t1 WHERE t1 MATCH 'a* b* c*'"
7 "SELECT docid, * FROM t1 WHERE t1 MATCH 'aa OR da'"
8 "SELECT docid, * FROM t1 WHERE t1 MATCH 'nosuchtoken'"
9 "SELECT docid, snippet(t1) FROM t1 WHERE t1 MATCH 'aa OR da'"
10 "SELECT docid, snippet(t1) FROM t1 WHERE t1 MATCH 'aa OR nosuchtoken'"
11 "SELECT docid, snippet(t1) FROM t1 WHERE t1 MATCH 'aa NEAR bb'"
12 "SELECT docid, snippet(t1) FROM t1 WHERE t1 MATCH '\"aa bb\"'"
13 "SELECT docid, content FROM t1 WHERE t1 MATCH 'aa NEAR/2 bb NEAR/3 cc'"
14 "SELECT docid, content FROM t1 WHERE t1 MATCH '\"aa bb cc\"'"
} {
unset -nocomplain A B C D
set A_list [list]
set B_list [list]
set C_list [list]
set D_list [list]
unset -nocomplain X
db eval "$query ORDER BY rowid ASC" X {
set A($X(docid)) [array get X]
lappend A_list $X(docid)
}
unset -nocomplain X
db eval "$query ORDER BY rowid DESC" X {
set B($X(docid)) [array get X]
lappend B_list $X(docid)
}
unset -nocomplain X
db eval "$query ORDER BY docid ASC" X {
set C($X(docid)) [array get X]
lappend C_list $X(docid)
}
unset -nocomplain X
db eval "$query ORDER BY docid DESC" X {
set D($X(docid)) [array get X]
lappend D_list $X(docid)
}
do_test $tn.1 { set A_list } [lsort -integer -increasing $A_list]
do_test $tn.2 { set B_list } [lsort -integer -decreasing $B_list]
do_test $tn.3 { set C_list } [lsort -integer -increasing $C_list]
do_test $tn.4 { set D_list } [lsort -integer -decreasing $D_list]
unset -nocomplain DATA
unset -nocomplain X
db eval "$query" X {
set DATA($X(docid)) [array get X]
}
do_test $tn.5 { lsort [array get A] } [lsort [array get DATA]]
do_test $tn.6 { lsort [array get B] } [lsort [array get DATA]]
do_test $tn.7 { lsort [array get C] } [lsort [array get DATA]]
do_test $tn.8 { lsort [array get D] } [lsort [array get DATA]]
if {[info exists CONTROL($tn)]} {
do_test $tn.9 { set CONTROL($tn) } [lsort [array get DATA]]
} else {
set CONTROL($tn) [lsort [array get DATA]]
}
}
}
unset -nocomplain CONTROL
set testprefix fts3sort
#-------------------------------------------------------------------------
# Tests for parsing the "order=asc" and "order=desc" directives.
#
foreach {tn param res} {
1 "order=asc" {0 {}}
2 "order=desc" {0 {}}
3 "order=dec" {1 {unrecognized order: dec}}
4 "order=xxx, order=asc" {1 {unrecognized order: xxx}}
5 "order=desc, order=asc" {0 {}}
} {
execsql { DROP TABLE IF EXISTS t1 }
do_catchsql_test 2.1.$tn "
CREATE VIRTUAL TABLE t1 USING fts4(a, b, $param)
" $res
}
do_execsql_test 2.2 {
BEGIN;
CREATE VIRTUAL TABLE t2 USING fts4(order=desc);
INSERT INTO t2 VALUES('aa bb');
INSERT INTO t2 VALUES('bb cc');
INSERT INTO t2 VALUES('cc aa');
SELECT docid FROM t2 WHERE t2 MATCH 'aa';
END;
} {3 1}
do_execsql_test 2.3 {
SELECT docid FROM t2 WHERE t2 MATCH 'aa';
} {3 1}
finish_test
+114 -20
View File
@@ -21,14 +21,12 @@ ifcapable !fts3 {
finish_test
return
}
if {[db eval {SELECT sqlite_compileoption_used('ENABLE_FTS4')}]==0} {
finish_test
return
}
do_test fts4aa-1.0 {
# 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 fts4aa_fill_table {} {
db eval {
CREATE VIRTUAL TABLE t1 USING fts4(words, tokenize porter);
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.');
@@ -1565,9 +1563,41 @@ INSERT INTO t1(docid,words) VALUES(1050025,'And Joseph took an oath of the child
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;
}
}
# The following is a list of queries to perform against the above
# FTS3/FTS4 database. We will be trying these queries in various
# configurations to ensure that they always return the same answers.
#
set fts4aa_queries {
{abraham}
{the king}
{"the king"}
{abraham OR joseph}
{ab* OR jos*}
{lived t*}
{spake hebrew}
{melchizedek}
{t* melchizedek}
{melchizedek t*}
}
unset -nocomplain fts4aa_res
# Set up the baseline results
#
do_test fts4aa-1.0 {
db eval {
CREATE VIRTUAL TABLE t1 USING fts4(words, tokenize porter);
}
fts4aa_fill_table
foreach q $::fts4aa_queries {
set r [db eval {SELECT docid FROM t1 WHERE words MATCH $q ORDER BY docid}]
set ::fts4aa_res($q) $r
}
} {}
# Legacy test cases
#
do_test fts4aa-1.1 {
db eval {
SELECT docid FROM t1 EXCEPT SELECT docid FROM t1_docsize
@@ -1587,50 +1617,114 @@ proc mit {blob} {
}
db func mit mit
do_test fts4aa-2.1 {
do_test fts4aa-1.3 {
db eval {
SELECT docid, mit(matchinfo(t1)) FROM t1 WHERE t1 MATCH 'melchizedek';
SELECT docid, mit(matchinfo(t1, 'pcxnal')) FROM t1 WHERE t1 MATCH 'melchizedek';
}
} {1014018 {1 1 1 1 1 1533 25 20}}
do_test fts4aa-2.2 {
do_test fts4aa-1.4 {
db eval {
SELECT docid, mit(matchinfo(t1)) FROM t1
SELECT docid, mit(matchinfo(t1, 'pcxnal')) FROM t1
WHERE t1 MATCH 'spake hebrew'
ORDER BY docid;
}
} {1039014 {2 1 1 40 40 1 6 6 1533 25 42} 1039017 {2 1 1 40 40 1 6 6 1533 25 26}}
do_test fts4aa-2.3 {
do_test fts4aa-1.5 {
db eval {
SELECT docid, mit(matchinfo(t1)) FROM t1
SELECT docid, mit(matchinfo(t1, 'pcxnal')) FROM t1
WHERE t1 MATCH 'laban overtook jacob'
ORDER BY docid;
}
} {1031025 {3 1 2 54 46 1 3 3 2 181 160 1533 25 24}}
do_test fts4aa-9.1 {
do_test fts4aa-1.6 {
db eval {
DELETE FROM t1 WHERE docid!=1050026;
SELECT hex(size) FROM t1_docsize;
SELECT hex(value) FROM t1_stat;
}
} {17 0117}
} {17 01176F}
do_test fts4aa-9.2 {
do_test fts4aa-1.7 {
db eval {
SELECT docid FROM t1 EXCEPT SELECT docid FROM t1_docsize
}
} {}
do_test fts4aa-9.3 {
do_test fts4aa-1.8 {
db eval {
SELECT docid FROM t1_docsize EXCEPT SELECT docid FROM t1
}
} {}
do_test fts4aa-9.4 {
do_test fts4aa-1.9 {
# Note: Token 'in' is being deferred in the following query.
db eval {
SELECT docid, mit(matchinfo(t1)) FROM t1
SELECT docid, mit(matchinfo(t1, 'pcxnal')) FROM t1
WHERE t1 MATCH 'joseph died in egypt'
ORDER BY docid;
}
} {1050026 {4 1 1 1 1 1 1 1 2 2 1 1 1 1 1 23 23}}
} {1050026 {4 1 1 1 1 1 1 1 2 1 1 1 1 1 1 23 23}}
# Should get the same search results from FTS3
#
do_test fts4aa-2.0 {
db eval {
DROP TABLE t1;
CREATE VIRTUAL TABLE t1 USING fts3(words, tokenize porter);
}
fts4aa_fill_table
} {}
unset -nocomplain ii
set ii 0
foreach {q r} [array get fts4aa_res] {
incr ii
do_test fts4aa-2.$ii {
db eval {SELECT docid FROM t1 WHERE words MATCH $::q ORDER BY docid}
} $r
}
# Should get the same search results when the page size is very large
#
do_test fts4aa-3.0 {
db close
file delete -force test.db
sqlite3 db test.db
db eval {
PRAGMA page_size=65536;
CREATE VIRTUAL TABLE t1 USING fts4(words, tokenize porter);
}
fts4aa_fill_table
} {}
unset -nocomplain ii
set ii 0
foreach {q r} [array get fts4aa_res] {
incr ii
do_test fts4aa-3.$ii {
db eval {SELECT docid FROM t1 WHERE words MATCH $::q ORDER BY docid}
} $r
}
# Should get the same search results when an authorizer prevents
# all PRAGMA statements.
#
proc no_pragma_auth {code arg1 arg2 arg3 arg4} {
if {$code=="SQLITE_PRAGMA"} {return SQLITE_DENY}
return SQLITE_OK;
}
do_test fts4aa-4.0 {
db auth ::no_pragma_auth
db eval {
DROP TABLE t1;
CREATE VIRTUAL TABLE t1 USING fts4(words, tokenize porter);
}
fts4aa_fill_table
} {}
unset -nocomplain ii
set ii 0
foreach {q r} [array get fts4aa_res] {
incr ii
do_test fts4aa-4.$ii {
db eval {SELECT docid FROM t1 WHERE words MATCH $::q ORDER BY docid}
} $r
}
finish_test
+28
View File
@@ -274,6 +274,34 @@ ifcapable compound&&attach {
set ::update_hook
} [list]
}
do_test hook-4.4 {
execsql {
CREATE TABLE t4(a UNIQUE, b);
INSERT INTO t4 VALUES(1, 'a');
INSERT INTO t4 VALUES(2, 'b');
}
set ::update_hook [list]
execsql {
REPLACE INTO t4 VALUES(1, 'c');
}
set ::update_hook
} [list INSERT main t4 3 ]
do_execsql_test hook-4.4.1 {
SELECT * FROM t4 ORDER BY a;
} {1 c 2 b}
do_test hook-4.4.2 {
set ::update_hook [list]
execsql {
PRAGMA recursive_triggers = on;
REPLACE INTO t4 VALUES(1, 'd');
}
set ::update_hook
} [list INSERT main t4 4 ]
do_execsql_test hook-4.4.3 {
SELECT * FROM t4 ORDER BY a;
} {1 d 2 b}
db update_hook {}
#
#----------------------------------------------------------------------------
+60
View File
@@ -326,4 +326,64 @@ do_test insert4-6.7 {
}
} {1 {constraint failed}}
# Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
# Disable the xfer optimization if the destination table contains
# a foreign key constraint
#
ifcapable foreignkey {
do_test insert4-7.1 {
set ::sqlite3_xferopt_count 0
execsql {
CREATE TABLE t7a(x INTEGER PRIMARY KEY); INSERT INTO t7a VALUES(123);
CREATE TABLE t7b(y INTEGER REFERENCES t7a);
CREATE TABLE t7c(z INT); INSERT INTO t7c VALUES(234);
INSERT INTO t7b SELECT * FROM t7c;
SELECT * FROM t7b;
}
} {234}
do_test insert4-7.2 {
set ::sqlite3_xferopt_count
} {1}
do_test insert4-7.3 {
set ::sqlite3_xferopt_count 0
execsql {
DELETE FROM t7b;
PRAGMA foreign_keys=ON;
}
catchsql {
INSERT INTO t7b SELECT * FROM t7c;
}
} {1 {foreign key constraint failed}}
do_test insert4-7.4 {
execsql {SELECT * FROM t7b}
} {}
do_test insert4-7.5 {
set ::sqlite3_xferopt_count
} {0}
do_test insert4-7.6 {
set ::sqlite3_xferopt_count 0
execsql {
DELETE FROM t7b; DELETE FROM t7c;
INSERT INTO t7c VALUES(123);
INSERT INTO t7b SELECT * FROM t7c;
SELECT * FROM t7b;
}
} {123}
do_test insert4-7.7 {
set ::sqlite3_xferopt_count
} {0}
do_test insert4-7.7 {
set ::sqlite3_xferopt_count 0
execsql {
PRAGMA foreign_keys=OFF;
DELETE FROM t7b;
INSERT INTO t7b SELECT * FROM t7c;
SELECT * FROM t7b;
}
} {123}
do_test insert4-7.8 {
set ::sqlite3_xferopt_count
} {1}
}
finish_test
+2 -2
View File
@@ -55,8 +55,8 @@ proc do_multiclient_test {varname script} {
uplevel set $varname $tn
uplevel $script
code2 { db2 close }
code3 { db3 close }
catch { code2 { db2 close } }
catch { code3 { db3 close } }
catch { close $::code2_chan }
catch { close $::code3_chan }
catch { db close }
+12
View File
@@ -894,6 +894,18 @@ ifcapable stat2&&utf16 {
}
}
# Test that if an OOM error occurs, aux-data is still correctly destroyed.
# This test case was causing either a memory-leak or an assert() failure
# at one point, depending on the configuration.
#
do_malloc_test 39 -tclprep {
sqlite3 db test.db
} -sqlbody {
SELECT test_auxdata('abc', 'def');
} -cleanup {
db close
}
# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
catch {db close}
+41
View File
@@ -567,5 +567,46 @@ if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
}
}
#-------------------------------------------------------------------------
# Test that you can vacuum a multiplex'ed DB.
ifcapable vacuum {
sqlite3_multiplex_shutdown
do_test multiplex-6.0.0 {
multiplex_delete test.db
sqlite3_multiplex_initialize "" 1
sqlite3 db test.db
multiplex_set db main 4096 16
} {SQLITE_OK}
do_test multiplex-6.1.0 {
execsql {
PRAGMA page_size=1024;
PRAGMA journal_mode=DELETE;
PRAGMA auto_vacuum=OFF;
}
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, randomblob($g_chunk_size));
INSERT INTO t1 VALUES(2, randomblob($g_chunk_size));
}
} {}
do_test multiplex-6.2.1 { file size [multiplex_name test.db 0] } [list $g_chunk_size]
do_test multiplex-6.2.2 { file size [multiplex_name test.db 1] } [list $g_chunk_size]
do_test multiplex-6.3.0 {
execsql { VACUUM }
} {}
do_test multiplex-6.99 {
db close
multiplex_delete test.db
sqlite3_multiplex_shutdown
} {SQLITE_OK}
}
catch { sqlite3_multiplex_shutdown }
finish_test
+8 -8
View File
@@ -42,31 +42,31 @@ do_test nan-1.1.1 {
db eval {SELECT x, typeof(x) FROM t1}
} {{} null}
if {$tcl_platform(platform) != "symbian"} {
do_test nan-1.1.2 {
do_realnum_test nan-1.1.2 {
sqlite3_bind_double $::STMT 1 +Inf
sqlite3_step $::STMT
sqlite3_reset $::STMT
db eval {SELECT x, typeof(x) FROM t1}
} {{} null inf real}
do_test nan-1.1.3 {
do_realnum_test nan-1.1.3 {
sqlite3_bind_double $::STMT 1 -Inf
sqlite3_step $::STMT
sqlite3_reset $::STMT
db eval {SELECT x, typeof(x) FROM t1}
} {{} null inf real -inf real}
do_test nan-1.1.4 {
do_realnum_test nan-1.1.4 {
sqlite3_bind_double $::STMT 1 -NaN
sqlite3_step $::STMT
sqlite3_reset $::STMT
db eval {SELECT x, typeof(x) FROM t1}
} {{} null inf real -inf real {} null}
do_test nan-1.1.5 {
do_realnum_test nan-1.1.5 {
sqlite3_bind_double $::STMT 1 NaN0
sqlite3_step $::STMT
sqlite3_reset $::STMT
db eval {SELECT x, typeof(x) FROM t1}
} {{} null inf real -inf real {} null {} null}
do_test nan-1.1.6 {
do_realnum_test nan-1.1.6 {
sqlite3_bind_double $::STMT 1 -NaN0
sqlite3_step $::STMT
sqlite3_reset $::STMT
@@ -231,12 +231,12 @@ if {$tcl_platform(platform) != "symbian"} {
# Do not run these tests on Symbian, as the Tcl port doesn't like to
# convert from floating point value "-inf" to a string.
#
do_test nan-4.7 {
do_realnum_test nan-4.7 {
db eval {DELETE FROM t1}
db eval "INSERT INTO t1 VALUES([string repeat 9 309].0)"
db eval {SELECT x, typeof(x) FROM t1}
} {inf real}
do_test nan-4.8 {
do_realnum_test nan-4.8 {
db eval {DELETE FROM t1}
db eval "INSERT INTO t1 VALUES(-[string repeat 9 309].0)"
db eval {SELECT x, typeof(x) FROM t1}
@@ -313,7 +313,7 @@ do_test nan-4.18 {
db eval {SELECT CAST(x AS text), typeof(x) FROM t1}
} {-9.88131291682493e-324 real}
do_test nan-4.20 {
do_realnum_test nan-4.20 {
db eval {DELETE FROM t1}
set big [string repeat 9 10000].0e-9000
db eval "INSERT INTO t1 VALUES($big)"
+1
View File
@@ -51,6 +51,7 @@ proc do_re_test {tn script expression} {
# a call to getcwd() may fail if there are no free file descriptors. So
# an error may be reported for either open() or getcwd() here.
#
puts "Possible valgrind error about invalid file descriptor follows:"
do_test 1.1.1 {
set ::log [list]
list [catch {
+10 -2
View File
@@ -441,6 +441,8 @@ do_test pager1.4.2.1 {
db close
tstvfs delete
} {}
if {$::tcl_platform(platform)!="windows"} {
do_test pager1.4.2.2 {
faultsim_restore_and_reopen
execsql {
@@ -473,6 +475,7 @@ do_test pager1.4.2.5 {
PRAGMA integrity_check;
}
} {4 ok}
}
do_test pager1.4.3.1 {
testvfs tstvfs -default 1
@@ -1548,6 +1551,7 @@ do_execsql_test pager1-13.1.1 {
UPDATE t1 SET b = a_string(400);
} {persist}
if {$::tcl_platform(platform)!="windows"} {
# Run transactions of increasing sizes. Eventually, one (or more than one)
# of these will write just enough content that one of the old headers created
# by the transaction in the block above lies immediately after the content
@@ -1570,7 +1574,9 @@ for {set nUp 1} {$nUp<64} {incr nUp} {
} {ok}
db2 close
}
}
if {$::tcl_platform(platform)!="windows"} {
# Same test as above. But this time with an index on the table.
#
do_execsql_test pager1-13.2.1 {
@@ -1591,6 +1597,7 @@ for {set nUp 1} {$nUp<64} {incr nUp} {
} {ok}
db2 close
}
}
db close
tv delete
@@ -1653,7 +1660,7 @@ for {set i 0} {$i<513} {incr i 3} {
testvfs tv -default 1
tv script xOpenCb
tv filter xOpen
proc xOpenCb {method filename} {
proc xOpenCb {method filename args} {
set ::file_len [string length $filename]
}
sqlite3 db test.db
@@ -2381,6 +2388,7 @@ do_test pager1-30.1 {
# file can still be rolled back. This is required for backward compatibility -
# versions of SQLite prior to 3.5.8 always set this field to zero.
#
if {$tcl_platform(platform)=="unix"} {
do_test pager1-31.1 {
faultsim_delete_and_reopen
execsql {
@@ -2408,7 +2416,7 @@ do_test pager1-31.1 {
sqlite3 db2 test.db2
execsql { PRAGMA integrity_check } db2
} {ok}
}
finish_test
+5
View File
@@ -20,6 +20,11 @@ if {[permutation] == "inmemory_journal"} {
return
}
if {$::tcl_platform(platform)=="windows"} {
finish_test
return
}
set a_string_counter 1
proc a_string {n} {
global a_string_counter
+3 -2
View File
@@ -179,10 +179,11 @@ test_suite "fts3" -prefix "" -description {
fts3atoken.test fts3b.test fts3c.test fts3cov.test fts3d.test
fts3defer.test fts3defer2.test fts3e.test fts3expr.test fts3expr2.test
fts3near.test fts3query.test fts3shared.test fts3snippet.test
fts3sort.test
fts3fault.test fts3malloc.test fts3matchinfo.test
fts3aux1.test fts3comp1.test
fts3aux1.test fts3comp1.test fts3auto.test
}
@@ -528,7 +529,7 @@ test_suite "inmemory_journal" -description {
stmt.test
# WAL mode is different.
wal*
wal* tkt-2d1a5c67d.test
}]
ifcapable mem3 {
+3
View File
@@ -202,6 +202,9 @@ do_test quota-3.2.9 {
set ::quota [list]
proc quota_callback {file limitvar size} {
upvar $limitvar limit
if {$::tcl_platform(platform)=="windows"} {
set file [ lindex [string map {\\ \/} $file] 0 ]
}
lappend ::quota $file $size
set limit 0
}
+16 -14
View File
@@ -19,19 +19,27 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
#
# These tests are only applicable on unix when pager pragma are
# These tests are only applicable when pager pragma are
# enabled. Also, since every test uses an ATTACHed database, they
# are only run when ATTACH is enabled.
#
if {$::tcl_platform(platform)!="unix"} {
finish_test
return
}
ifcapable !pager_pragmas||!attach {
finish_test
return
}
set sqlite_sync_count 0
proc cond_incr_sync_count {adj} {
global sqlite_sync_count
if {$::tcl_platform(platform) == "windows"} {
incr sqlite_sync_count $adj
} {
ifcapable !dirsync {
incr sqlite_sync_count $adj
}
}
}
do_test sync-1.1 {
set sqlite_sync_count 0
file delete -force test2.db
@@ -42,9 +50,7 @@ do_test sync-1.1 {
ATTACH DATABASE 'test2.db' AS db2;
CREATE TABLE db2.t2(x,y);
}
ifcapable !dirsync {
incr sqlite_sync_count 2
}
cond_incr_sync_count 2
set sqlite_sync_count
} 8
ifcapable pager_pragmas {
@@ -58,9 +64,7 @@ ifcapable pager_pragmas {
INSERT INTO t2 VALUES(3,4);
COMMIT;
}
ifcapable !dirsync {
incr sqlite_sync_count 3
}
cond_incr_sync_count 3
set sqlite_sync_count
} 8
}
@@ -74,9 +78,7 @@ do_test sync-1.3 {
INSERT INTO t2 VALUES(5,6);
COMMIT;
}
ifcapable !dirsync {
incr sqlite_sync_count 3
}
cond_incr_sync_count 3
set sqlite_sync_count
} 10
ifcapable pager_pragmas {
+38 -2
View File
@@ -354,6 +354,31 @@ proc do_test {name cmd expected} {
flush stdout
}
proc filepath_normalize {p} {
# test cases should be written to assume "unix"-like file paths
if {$::tcl_platform(platform)!="unix"} {
# lreverse*2 as a hack to remove any unneeded {} after the string map
lreverse [lreverse [string map {\\ /} [regsub -nocase -all {[a-z]:[/\\]+} $p {/}]]]
} {
set p
}
}
proc do_filepath_test {name cmd expected} {
uplevel [list do_test $name [
subst -nocommands { filepath_normalize [ $cmd ] }
] [filepath_normalize $expected]]
}
proc realnum_normalize {r} {
# different TCL versions display floating point values differently.
string map {1.#INF inf Inf inf .0e e} [regsub -all {(e[+-])0+} $r {\1}]
}
proc do_realnum_test {name cmd expected} {
uplevel [list do_test $name [
subst -nocommands { realnum_normalize [ $cmd ] }
] [realnum_normalize $expected]]
}
proc fix_testname {varname} {
upvar $varname testname
if {[info exists ::testprefix]
@@ -365,11 +390,11 @@ proc fix_testname {varname} {
proc do_execsql_test {testname sql {result {}}} {
fix_testname testname
uplevel do_test $testname [list "execsql {$sql}"] [list [list {*}$result]]
uplevel do_test [list $testname] [list "execsql {$sql}"] [list [list {*}$result]]
}
proc do_catchsql_test {testname sql result} {
fix_testname testname
uplevel do_test $testname [list "catchsql {$sql}"] [list $result]
uplevel do_test [list $testname] [list "catchsql {$sql}"] [list $result]
}
proc do_eqp_test {name sql res} {
uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res]
@@ -747,6 +772,17 @@ proc integrity_check {name {db db}} {
}
}
# Return true if the SQL statement passed as the second argument uses a
# statement transaction.
#
proc sql_uses_stmt {db sql} {
set stmt [sqlite3_prepare $db $sql -1 dummy]
set uses [uses_stmt_journal $stmt]
sqlite3_finalize $stmt
return $uses
}
proc fix_ifcapable_expr {expr} {
set ret ""
set state 0
+127
View File
@@ -0,0 +1,127 @@
# 2011 May 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library. Specifically,
# it tests that ticket [2d1a5c67dfc2363e44f29d9bbd57f7331851390a] has
# been resolved.
#
#
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tkt-2d1a5c67d
ifcapable {!wal || !vtab} {finish_test; return}
for {set ii 1} {$ii<=10} {incr ii} {
do_test tkt-2d1a5c67d.1.$ii {
db close
forcedelete test.db test.db-wal
sqlite3 db test.db
db eval "PRAGMA cache_size=$::ii"
db eval {
PRAGMA journal_mode=WAL;
CREATE TABLE t1(a,b);
CREATE INDEX t1b ON t1(b);
CREATE TABLE t2(x,y UNIQUE);
INSERT INTO t2 VALUES(3,4);
BEGIN;
INSERT INTO t1(a,b) VALUES(1,2);
SELECT 'A', * FROM t2 WHERE y=4;
SELECT 'B', * FROM t1;
COMMIT;
SELECT 'C', * FROM t1;
}
} {wal A 3 4 B 1 2 C 1 2}
}
db close
forcedelete test.db test.db-wal
sqlite3 db test.db
register_wholenumber_module db
db eval {
PRAGMA journal_mode=WAL;
CREATE TABLE t1(a,b);
CREATE INDEX t1b ON t1(b);
CREATE TABLE t2(x,y);
CREATE VIRTUAL TABLE nums USING wholenumber;
INSERT INTO t2 SELECT value, randomblob(1000) FROM nums
WHERE value BETWEEN 1 AND 1000;
}
for {set ii 1} {$ii<=10} {incr ii} {
do_test tkt-2d1a5c67d.2.$ii {
db eval "PRAGMA cache_size=$::ii"
db eval {
DELETE FROM t1;
BEGIN;
INSERT INTO t1(a,b) VALUES(1,2);
SELECT sum(length(y)) FROM t2;
COMMIT;
SELECT * FROM t1;
}
} {1000000 1 2}
}
db close
sqlite3 db test.db
do_execsql_test 3.1 {
PRAGMA cache_size = 10;
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
CREATE TABLE t4(a);
}
do_execsql_test 3.2 {
INSERT INTO t3 VALUES(NULL, randomblob(500));
INSERT INTO t3 SELECT NULL, b||b FROM t3; -- 2
INSERT INTO t3 SELECT NULL, b||b FROM t3; -- 4
INSERT INTO t3 SELECT NULL, b||b FROM t3; -- 8
INSERT INTO t3 SELECT NULL, b||b FROM t3; -- 16
INSERT INTO t3 SELECT NULL, b||b FROM t3; -- 32
INSERT INTO t3 SELECT NULL, b||b FROM t3; -- 64
INSERT INTO t3 SELECT NULL, b||b FROM t3; -- 128
}
do_execsql_test 3.3 {
BEGIN;
INSERT INTO t4 VALUES('xyz');
}
do_test 3.4 {
set blobs [list]
for {set i 1} {$i<100} {incr i} {
set b [db incrblob -readonly t3 b $i]
read $b
lappend blobs $b
}
execsql COMMIT
execsql { SELECT * FROM t4 WHERE a = 'xyz' }
} {xyz}
do_test 3.5 {
foreach b $blobs { close $b }
execsql { SELECT * FROM t4 WHERE a = 'xyz' }
} {xyz}
# Check that recovery works on the WAL file.
#
forcedelete test.db2-wal test.db2
do_test 3.6 {
file copy test.db-wal test.db2-wal
file copy test.db test.db2
sqlite3 db2 test.db2
execsql { SELECT * FROM t4 WHERE a = 'xyz' } db2
} {xyz}
finish_test
+52
View File
@@ -0,0 +1,52 @@
# 2011 June 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 contains tests for SQLite. Specifically, it tests that SQLite
# does not crash and an error is returned if localhost() fails. This
# is the problem reported by ticket 91e2e8ba6f.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tkt-91e2e8ba6f
do_execsql_test 1.1 {
CREATE TABLE t1(x INTEGER, y REAL);
INSERT INTO t1 VALUES(11, 11);
} {}
do_execsql_test 1.2 {
SELECT x/10, y/10 FROM t1;
} {1 1.1}
do_execsql_test 1.3 {
SELECT x/10, y/10 FROM (SELECT * FROM t1);
} {1 1.1}
do_execsql_test 1.4 {
SELECT x/10, y/10 FROM (SELECT * FROM t1 LIMIT 5 OFFSET 0);
} {1 1.1}
do_execsql_test 1.5 {
SELECT x/10, y/10 FROM (SELECT * FROM t1 LIMIT 5 OFFSET 0) LIMIT 5 OFFSET 0;
} {1 1.1}
do_execsql_test 1.6 {
SELECT a.x/10, a.y/10 FROM
(SELECT * FROM t1 LIMIT 5 OFFSET 0) AS a, t1 AS b WHERE a.x = b.x
LIMIT 5 OFFSET 0;
} {1 1.1}
do_execsql_test 1.7 {
CREATE VIEW v1 AS SELECT * FROM t1 LIMIT 5;
SELECT a.x/10, a.y/10 FROM v1 AS a, t1 AS b WHERE a.x = b.x LIMIT 5 OFFSET 0;
} {1 1.1}
finish_test
+38
View File
@@ -0,0 +1,38 @@
# 2011 June 21
#
# 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 tests for SQLite. Specifically, it tests that SQLite
# does not crash and an error is returned if localhost() fails. This
# is the problem reported by ticket bd484a090c.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tkt-bd484a090c
do_test 1.1 {
lindex [catchsql { SELECT datetime('now', 'localtime') }] 0
} {0}
do_test 1.2 {
lindex [catchsql { SELECT datetime('now', 'utc') }] 0
} {0}
sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 1
do_test 2.1 {
catchsql { SELECT datetime('now', 'localtime') }
} {1 {local time unavailable}}
do_test 2.2 {
catchsql { SELECT datetime('now', 'utc') }
} {1 {local time unavailable}}
sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0
finish_test
+1 -1
View File
@@ -25,7 +25,7 @@ ifcapable !altertable {
return
}
do_test tkt3838-1.1 {
do_realnum_test tkt3838-1.1 {
db eval {
PRAGMA encoding=UTF16;
CREATE TABLE t1(x);
+4 -4
View File
@@ -36,21 +36,21 @@ if {[working_64bit_int]} {
}
} {-1 integer}
}
do_test tkt3922.2 {
do_realnum_test tkt3922.2 {
execsql {
DELETE FROM t1;
INSERT INTO t1 VALUES('-9223372036854775809');
SELECT a, typeof(a) FROM t1;
}
} {-9.22337203685478e+18 real}
do_test tkt3922.3 {
do_realnum_test tkt3922.3 {
execsql {
DELETE FROM t1;
INSERT INTO t1 VALUES('-9223372036854776832');
SELECT a, typeof(a) FROM t1;
}
} {-9.22337203685478e+18 real}
do_test tkt3922.4 {
do_realnum_test tkt3922.4 {
execsql {
DELETE FROM t1;
INSERT INTO t1 VALUES('-9223372036854776833');
@@ -78,7 +78,7 @@ if {[working_64bit_int]} {
}
} {1 integer}
}
do_test tkt3922.6 {
do_realnum_test tkt3922.6 {
execsql {
DELETE FROM t1;
INSERT INTO t1 VALUES('9223372036854775808');
+3 -3
View File
@@ -141,10 +141,10 @@ ifcapable fts3 {
INSERT INTO x1(x1) VALUES('optimize');
} {
"INSERT INTO x1(x1) VALUES('optimize');"
"-- SELECT idx, start_block, leaves_end_block, end_block, root FROM 'main'.'x1_segdir' ORDER BY level DESC, idx ASC"
"-- SELECT count(*), max(level) FROM 'main'.'x1_segdir'"
"-- SELECT idx, start_block, leaves_end_block, end_block, root FROM 'main'.'x1_segdir' WHERE level BETWEEN ? AND ?ORDER BY level DESC, idx ASC"
"-- SELECT max(level) FROM 'main'.'x1_segdir' WHERE level BETWEEN ? AND ?"
"-- SELECT coalesce((SELECT max(blockid) FROM 'main'.'x1_segments') + 1, 1)"
"-- DELETE FROM 'main'.'x1_segdir'"
"-- DELETE FROM 'main'.'x1_segdir' WHERE level BETWEEN ? AND ?"
"-- INSERT INTO 'main'.'x1_segdir' VALUES(?,?,?,?,?,?)"
}
}
+35 -35
View File
@@ -228,25 +228,25 @@ foreach {n tdefn rc} {
}
do_test triggerC-2.2 {
execsql {
execsql "
CREATE TABLE t22(x);
CREATE TRIGGER t22a AFTER INSERT ON t22 BEGIN
INSERT INTO t22 SELECT x + (SELECT max(x) FROM t22) FROM t22;
END;
CREATE TRIGGER t22b BEFORE INSERT ON t22 BEGIN
SELECT CASE WHEN (SELECT count(*) FROM t22) >= 100
SELECT CASE WHEN (SELECT count(*) FROM t22) >= [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]
THEN RAISE(IGNORE)
ELSE NULL END;
END;
INSERT INTO t22 VALUES(1);
SELECT count(*) FROM t22;
}
} {100}
"
} [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]]
do_test triggerC-2.3 {
execsql {
execsql "
CREATE TABLE t23(x PRIMARY KEY);
CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN
@@ -254,15 +254,15 @@ do_test triggerC-2.3 {
END;
CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN
SELECT CASE WHEN new.x>500
SELECT CASE WHEN new.x>[expr $SQLITE_MAX_TRIGGER_DEPTH / 2]
THEN RAISE(IGNORE)
ELSE NULL END;
END;
INSERT INTO t23 VALUES(1);
SELECT count(*) FROM t23;
}
} {500}
"
} [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]]
#-----------------------------------------------------------------------
@@ -288,12 +288,12 @@ do_test triggerC-3.1.3 {
} {}
do_test triggerC-3.2.1 {
execsql {
execsql "
CREATE TABLE t3b(x);
CREATE TRIGGER t3bi AFTER INSERT ON t3b WHEN new.x<2000 BEGIN
CREATE TRIGGER t3bi AFTER INSERT ON t3b WHEN new.x<[expr $SQLITE_MAX_TRIGGER_DEPTH * 2] BEGIN
INSERT INTO t3b VALUES(new.x+1);
END;
}
"
catchsql {
INSERT INTO t3b VALUES(1);
}
@@ -303,39 +303,39 @@ do_test triggerC-3.2.2 {
} {}
do_test triggerC-3.3.1 {
catchsql {
INSERT INTO t3b VALUES(1001);
}
catchsql "
INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH + 1]);
"
} {0 {}}
do_test triggerC-3.3.2 {
db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {1000 2000 1001}
} [list $SQLITE_MAX_TRIGGER_DEPTH [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH + 1]]
do_test triggerC-3.4.1 {
catchsql {
catchsql "
DELETE FROM t3b;
INSERT INTO t3b VALUES(999);
}
INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH - 1]);
"
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.4.2 {
db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {0 {} {}}
do_test triggerC-3.5.1 {
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 100
catchsql {
INSERT INTO t3b VALUES(1901);
}
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH [expr $SQLITE_MAX_TRIGGER_DEPTH / 10]
catchsql "
INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10) + 1]);
"
} {0 {}}
do_test triggerC-3.5.2 {
db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {100 2000 1901}
} [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 10] [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10) + 1]]
do_test triggerC-3.5.3 {
catchsql {
catchsql "
DELETE FROM t3b;
INSERT INTO t3b VALUES(1900);
}
INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10)]);
"
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.5.4 {
db eval {SELECT count(*), max(x), min(x) FROM t3b}
@@ -343,25 +343,25 @@ do_test triggerC-3.5.4 {
do_test triggerC-3.6.1 {
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1
catchsql {
INSERT INTO t3b VALUES(2000);
}
catchsql "
INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH * 2]);
"
} {0 {}}
do_test triggerC-3.6.2 {
db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {1 2000 2000}
} [list 1 [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH * 2]]
do_test triggerC-3.6.3 {
catchsql {
catchsql "
DELETE FROM t3b;
INSERT INTO t3b VALUES(1999);
}
INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - 1]);
"
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.6.4 {
db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {0 {} {}}
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH $SQLITE_MAX_TRIGGER_DEPTH
#-----------------------------------------------------------------------
# This next block of tests, triggerC-4.*, checks that affinity
+1 -1
View File
@@ -21,7 +21,7 @@ source $testdir/tester.tcl
# A variable with only a string representation comes in as TEXT
do_test types3-1.1 {
set V {}
append V {}
append V x
concat [tcl_variable_type V] [execsql {SELECT typeof(:V)}]
} {string text}
+3
View File
@@ -57,6 +57,9 @@ foreach idxmode {ordered unordered} {
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)}}
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)}}
} {
do_eqp_test 1.$idxmode.$tn $sql $r($idxmode)
}
+310
View File
@@ -0,0 +1,310 @@
# 2011 April 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Test organization:
#
# 1.*: That file names are correctly extracted from URIs.
# 2.*: That URI options (query parameters) are correctly extracted from URIs.
# 3.*: That specifying an unknown VFS causes an error.
# 4.*: Tests for specifying other options (other than "vfs").
# 5.*: Test using a different VFS with an attached database.
# 6.*: Test that authorities other than "" and localhost cause errors.
# 7.*: Test that a read-write db can be attached to a read-only connection.
#
set testprefix uri
db close
sqlite3_shutdown
sqlite3_config_uri 1
#-------------------------------------------------------------------------
# Test that file names are correctly extracted from URIs.
#
foreach {tn uri file} {
1 test.db test.db
2 file:test.db test.db
3 file://PWD/test.db test.db
4 file:PWD/test.db test.db
5 file:test.db?mork=1 test.db
6 file:test.db?mork=1&tonglor=2 test.db
7 file:test.db?mork=1#boris test.db
8 file:test.db#boris test.db
9 test.db#boris test.db#boris
10 file:test%2Edb test.db
11 file file
12 http:test.db http:test.db
13 file:test.db%00extra test.db
14 file:testdb%00.db%00extra testdb
15 test.db?mork=1#boris test.db?mork=1#boris
16 file://localhostPWD/test.db%3Fhello test.db?hello
} {
if {$tcl_platform(platform)=="windows"} {
if {$tn>14} break
set uri [string map [list PWD /[pwd]] $uri]
} else {
set uri [string map [list PWD [pwd]] $uri]
}
if {[file isdir $file]} {error "$file is a directory"}
forcedelete $file
do_test 1.$tn.1 { file exists $file } 0
set DB [sqlite3_open $uri]
do_test 1.$tn.2 { file exists $file } 1
sqlite3_close $DB
forcedelete $file
do_test 1.$tn.3 { file exists $file } 0
sqlite3 db xxx.db
catchsql { ATTACH $uri AS aux }
do_test 1.$tn.4 { file exists $file } 1
db close
}
#-------------------------------------------------------------------------
# Test that URI query parameters are passed through to the VFS layer
# correctly.
#
testvfs tvfs2
testvfs tvfs -default 1
tvfs filter xOpen
tvfs script open_method
proc open_method {method file arglist} {
set ::arglist $arglist
}
foreach {tn uri kvlist} {
1 file:test.db?hello=world {hello world}
2 file:test.db?hello&world {hello {} world {}}
3 file:test.db?hello=1&world=2&vfs=tvfs {hello 1 world 2 vfs tvfs}
4 file:test.db?hello=1&world=2&vfs=tvfs2 {}
5 file:test.db?%68%65%6C%6C%6F=%77%6F%72%6C%64 {hello world}
6 file:testdb%00.db?hello%00extra=world%00ex {hello world}
7 file:testdb%00.db?hello%00=world%00 {hello world}
8 file:testdb%00.db?=world&xyz=abc {xyz abc}
9 file:test.db?%00hello=world&xyz=abc {xyz abc}
10 file:test.db?hello=%00world&xyz= {hello {} xyz {}}
11 file:test.db?=#ravada {}
12 file:test.db?&&&&&&&&hello=world&&&&&&& {hello world}
13 test.db?&&&&&&&&hello=world&&&&&&& {}
14 http:test.db?hello&world {}
} {
if {$tcl_platform(platform) == "windows" && $tn>12} {
continue
}
set ::arglist ""
set DB [sqlite3_open $uri]
do_test 2.$tn.1 { set ::arglist } $kvlist
sqlite3_close $DB
sqlite3 db xxx.db
set ::arglist ""
execsql { ATTACH $uri AS aux }
do_test 2.$tn.2 { set ::arglist } $kvlist
db close
}
tvfs delete
tvfs2 delete
#-------------------------------------------------------------------------
# Test that specifying a non-existent VFS raises an error.
#
do_test 3.1 {
list [catch { sqlite3 db "file:test.db?vfs=nosuchvfs" } msg] $msg
} {1 {no such vfs: nosuchvfs}}
#-------------------------------------------------------------------------
# Test some of the other options (other than "vfs").
#
foreach {tn mode create_ok write_ok readonly_ok} {
1 ro 0 0 1
2 rw 0 1 0
3 rwc 1 1 0
} {
catch { db close }
forcedelete test.db
set A(1) {0 {}}
set A(0) {1 {unable to open database file}}
do_test 4.1.$tn.1 {
list [catch {sqlite3 db "file:test.db?mode=$mode"} msg] $msg
} $A($create_ok)
catch { db close }
forcedelete test.db
sqlite3 db test.db
db eval { CREATE TABLE t1(a, b) }
db close
set A(1) {0 {}}
set A(0) {1 {attempt to write a readonly database}}
do_test 4.1.$tn.2 {
sqlite3 db "file:test.db?mode=$mode"
catchsql { INSERT INTO t1 VALUES(1, 2) }
} $A($write_ok)
set A(1) {0 {}}
set A(0) [list 1 "access mode not allowed: $mode"]
do_test 4.1.$tn.3 {
list [catch {sqlite3 db "file:test.db?mode=$mode" -readonly 1} msg] $msg
} $A($readonly_ok)
}
set orig [sqlite3_enable_shared_cache]
foreach {tn options sc_default is_shared} {
1 "" 1 1
2 "cache=private" 1 0
3 "cache=shared" 1 1
4 "" 0 0
5 "cache=private" 0 0
6 "cache=shared" 0 1
} {
catch { db close }
forcedelete test.db
sqlite3_enable_shared_cache 1
sqlite3 db2 test.db
db2 eval {CREATE TABLE t1(a, b)}
sqlite3_enable_shared_cache $sc_default
sqlite3 db "file:test.db?$options"
db eval {SELECT * FROM t1}
set A(1) {1 {database table is locked: t1}}
set A(0) {0 {}}
do_test 4.2.$tn {
db2 eval {BEGIN; INSERT INTO t1 VALUES(1, 2);}
catchsql { SELECT * FROM t1 }
} $A($is_shared)
db2 close
}
do_test 4.3.1 {
list [catch {sqlite3 db "file:test.db?mode=rc"} msg] $msg
} {1 {no such access mode: rc}}
do_test 4.3.2 {
list [catch {sqlite3 db "file:test.db?cache=public"} msg] $msg
} {1 {no such cache mode: public}}
#-------------------------------------------------------------------------
# Test that things work if an ATTACHed database uses a different VFS than
# the main database. The important point is that for all operations
# involving the ATTACHed database, the correct versions of the following
# VFS are used for all operations involving the attached database.
#
# xOpen
# xDelete
# xAccess
# xFullPathname
#
# This block of code creates two VFS - "tvfs1" and "tvfs2". Each time one
# of the above methods is called using "tvfs1", global variable ::T1(X) is
# set, where X is the file-name the method is called on. Calls to the above
# methods using "tvfs2" set entries in the global T2 array.
#
testvfs tvfs1
tvfs1 filter {xOpen xDelete xAccess xFullPathname}
tvfs1 script tvfs1_callback
proc tvfs1_callback {method filename args} {
set ::T1([file tail $filename]) 1
}
testvfs tvfs2
tvfs2 filter {xOpen xDelete xAccess xFullPathname}
tvfs2 script tvfs2_callback
proc tvfs2_callback {method filename args} {
set ::T2([file tail $filename]) 1
}
catch {db close}
eval forcedelete [glob test.db*]
do_test 5.1.1 {
sqlite3 db file:test.db1?vfs=tvfs1
execsql {
ATTACH 'file:test.db2?vfs=tvfs2' AS aux;
PRAGMA main.journal_mode = PERSIST;
PRAGMA aux.journal_mode = PERSIST;
CREATE TABLE t1(a, b);
CREATE TABLE aux.t2(a, b);
PRAGMA main.journal_mode = WAL;
PRAGMA aux.journal_mode = WAL;
INSERT INTO t1 VALUES('x', 'y');
INSERT INTO t2 VALUES('x', 'y');
}
lsort [array names ::T1]
} {test.db1 test.db1-journal test.db1-wal}
do_test 5.1.2 {
lsort [array names ::T2]
} {test.db2 test.db2-journal test.db2-wal}
db close
tvfs1 delete
tvfs2 delete
#-------------------------------------------------------------------------
# Check that only "" and "localhost" are acceptable as authorities.
#
catch {db close}
foreach {tn uri res} {
1 "file://localhost/PWD/test.db" {not an error}
2 "file:///PWD/test.db" {not an error}
3 "file:/PWD/test.db" {not an error}
4 "file://l%6Fcalhost/PWD/test.db" {invalid uri authority: l%6Fcalhost}
5 "file://lbcalhost/PWD/test.db" {invalid uri authority: lbcalhost}
6 "file://x/PWD/test.db" {invalid uri authority: x}
} {
if {$tcl_platform(platform)=="windows"} {
set uri [string map [list PWD [string range [pwd] 3 end]] $uri]
} else {
set uri [string map [list PWD [string range [pwd] 1 end]] $uri]
}
do_test 6.$tn {
set DB [sqlite3_open $uri]
sqlite3_errmsg $DB
} $res
catch { sqlite3_close $DB }
}
forcedelete test.db test.db2
do_test 7.1 {
sqlite3 db test.db
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
ATTACH 'test.db2' AS aux;
CREATE TABLE aux.t2(a, b);
INSERT INTO t1 VALUES('a', 'b');
}
db close
} {}
do_test 7.2 {
sqlite3 db file:test.db?mode=ro
execsql { ATTACH 'file:test.db2?mode=rw' AS aux }
} {}
do_execsql_test 7.3 {
INSERT INTO t2 VALUES('c', 'd')
} {}
do_catchsql_test 7.4 {
INSERT INTO t1 VALUES(3, 4)
} {1 {attempt to write a readonly database}}
finish_test
+13
View File
@@ -23,6 +23,18 @@ set testprefix wal2
ifcapable !wal {finish_test ; return }
set sqlite_sync_count 0
proc cond_incr_sync_count {adj} {
global sqlite_sync_count
if {$::tcl_platform(platform) == "windows"} {
incr sqlite_sync_count $adj
} {
ifcapable !dirsync {
incr sqlite_sync_count $adj
}
}
}
proc set_tvfs_hdr {file args} {
# Set $nHdr to the number of bytes in the wal-index header:
@@ -1189,6 +1201,7 @@ foreach {tn sql reslist} {
} {10 0 5 5 0 2 2}
do_test wal2-14.$tn.3 {
cond_incr_sync_count 1
list $sqlite_sync_count $sqlite_fullsync_count
} [lrange $reslist 0 1]
+8 -1
View File
@@ -235,7 +235,14 @@ foreach {testprefix do_wal_checkpoint} {
do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
do_test 2.3.$tn.6 { file_page_counts } {1 7 1 7}
do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 7 5}
do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7}
if {$tcl_platform(platform) == "windows"} {
# on unix, the size_hint is a no-op if no chunk size is set.
# the windows implementation does not have a similar check,
# and because of this, the db file size has an extra page.
do_test 2.3.$tn.8 { file_page_counts } {2 7 2 7}
} {
do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7}
}
}
# Check that checkpoints block on the correct locks. And respond correctly
+118
View File
@@ -0,0 +1,118 @@
# 2011 May 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 regression tests for SQLite library. The
# focus of this file is testing the PRAGMA journal_size_limit when
# in WAL mode.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !wal {finish_test ; return }
# Case 1: No size limit. Journal can get large.
#
do_test wal7-1.0 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
PRAGMA page_size=1024;
PRAGMA journal_mode=WAL;
PRAGMA wal_autocheckpoint=50; -- 50 pages
CREATE TABLE t1(x, y UNIQUE);
INSERT INTO t1 VALUES(1,2);
INSERT INTO t1 VALUES(zeroblob(200000),4);
CREATE TABLE t2(z);
DELETE FROM t1;
INSERT INTO t2 SELECT x FROM t1;
}
expr {[file size test.db-wal]>50*1100}
} 1
do_test wal7-1.1 {
db eval {PRAGMA wal_checkpoint}
expr {[file size test.db-wal]>50*1100}
} 1
do_test wal7-1.2 {
db eval {INSERT INTO t2 VALUES('hi');}
expr {[file size test.db-wal]>50*1100}
} 1
# Case 2: Size limit at half the autocheckpoint size.
#
do_test wal7-2.0 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
PRAGMA page_size=1024;
PRAGMA journal_mode=WAL;
PRAGMA wal_autocheckpoint=50; -- 50 pages
PRAGMA journal_size_limit=25000;
CREATE TABLE t1(x, y UNIQUE);
INSERT INTO t1 VALUES(1,2);
INSERT INTO t1 VALUES(zeroblob(200000),4);
CREATE TABLE t2(z);
DELETE FROM t1;
INSERT INTO t2 VALUES(1);
}
file size test.db-wal
} 25000
# Case 3: Size limit of zero.
#
do_test wal7-3.0 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
PRAGMA page_size=1024;
PRAGMA journal_mode=WAL;
PRAGMA wal_autocheckpoint=50; -- 50 pages
PRAGMA journal_size_limit=0;
CREATE TABLE t1(x, y UNIQUE);
INSERT INTO t1 VALUES(1,2);
INSERT INTO t1 VALUES(zeroblob(200000),4);
CREATE TABLE t2(z);
DELETE FROM t1;
INSERT INTO t2 VALUES(1);
}
set sz [file size test.db-wal]
expr {$sz>0 && $sz<13700}
} 1
# Case 4: Size limit set before going WAL
#
do_test wal7-4.0 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
PRAGMA page_size=1024;
PRAGMA journal_size_limit=25000;
PRAGMA journal_mode=WAL;
PRAGMA wal_autocheckpoint=50; -- 50 pages
CREATE TABLE t1(x, y UNIQUE);
INSERT INTO t1 VALUES(1,2);
INSERT INTO t1 VALUES(zeroblob(200000),4);
CREATE TABLE t2(z);
DELETE FROM t1;
INSERT INTO t2 VALUES(1);
}
set sz [file size test.db-wal]
} 25000
finish_test
+161
View File
@@ -0,0 +1,161 @@
# 2011 May 09
#
# 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 tests for using WAL databases in read-only mode.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
set ::testprefix walro
# These tests are only going to work on unix.
#
if {$::tcl_platform(platform) != "unix"} {
finish_test
return
}
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.
#
code1 { db close }
code2 { db2 close }
code3 { db3 close }
forcedelete test.db
forcedelete walro
foreach c {code1 code2 code3} {
$c {
sqlite3_shutdown
sqlite3_config_uri 1
}
}
file mkdir walro
do_test 1.1.1 {
code2 { sqlite3 db2 test.db }
sql2 {
PRAGMA journal_mode = WAL;
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES('a', 'b');
}
file exists test.db-shm
} {1}
do_test 1.1.2 {
file attributes test.db-shm -permissions r--r--r--
code1 { sqlite3 db file:test.db?readonly_shm=1 }
} {}
do_test 1.1.3 { sql1 "SELECT * FROM t1" } {a b}
do_test 1.1.4 { sql2 "INSERT INTO t1 VALUES('c', 'd')" } {}
do_test 1.1.5 { sql1 "SELECT * FROM t1" } {a b c d}
# Check that the read-only connection cannot write or checkpoint the db.
#
do_test 1.1.6 {
csql1 "INSERT INTO t1 VALUES('e', 'f')"
} {1 {attempt to write a readonly database}}
do_test 1.1.7 {
csql1 "PRAGMA wal_checkpoint"
} {1 {attempt to write a readonly database}}
do_test 1.1.9 { sql2 "INSERT INTO t1 VALUES('e', 'f')" } {}
do_test 1.1.10 { sql1 "SELECT * FROM t1" } {a b c d e f}
do_test 1.1.11 {
sql2 {
INSERT INTO t1 VALUES('g', 'h');
PRAGMA wal_checkpoint;
}
set {} {}
} {}
do_test 1.1.12 { sql1 "SELECT * FROM t1" } {a b c d e f g h}
do_test 1.1.13 { sql2 "INSERT INTO t1 VALUES('i', 'j')" } {}
do_test 1.2.1 {
code2 { db2 close }
code1 { db close }
list [file exists test.db-wal] [file exists test.db-shm]
} {1 1}
do_test 1.2.2 {
code1 { sqlite3 db file:test.db?readonly_shm=1 }
sql1 { SELECT * FROM t1 }
} {a b c d e f g h i j}
do_test 1.2.3 {
code1 { db close }
file attributes test.db-shm -permissions rw-r--r--
hexio_write test.db-shm 0 01020304
file attributes test.db-shm -permissions r--r--r--
code1 { sqlite3 db file:test.db?readonly_shm=1 }
csql1 { SELECT * FROM t1 }
} {1 {attempt to write a readonly database}}
do_test 1.2.4 {
code1 { sqlite3_extended_errcode db }
} {SQLITE_READONLY_RECOVERY}
do_test 1.2.5 {
file attributes test.db-shm -permissions rw-r--r--
code2 { sqlite3 db2 test.db }
sql2 "SELECT * FROM t1"
} {a b c d e f g h i j}
file attributes test.db-shm -permissions r--r--r--
do_test 1.2.6 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j}
do_test 1.2.7 {
sql2 {
PRAGMA wal_checkpoint;
INSERT INTO t1 VALUES('k', 'l');
}
set {} {}
} {}
do_test 1.2.8 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j k l}
# Now check that if the readonly_shm option is not supplied, or if it
# is set to zero, it is not possible to connect to the database without
# read-write access to the shm.
do_test 1.3.1 {
code1 { db close }
code1 { sqlite3 db test.db }
csql1 { SELECT * FROM t1 }
} {1 {unable to open database file}}
# Also test that if the -shm file can be opened for read/write access,
# it is, even if readonly_shm=1 is present in the URI.
do_test 1.3.2.1 {
code1 { db close }
code2 { db2 close }
file exists test.db-shm
} {0}
do_test 1.3.2.2 {
code1 { sqlite3 db file:test.db?readonly_shm=1 }
sql1 { SELECT * FROM t1 }
} {a b c d e f g h i j k l}
do_test 1.3.2.3 {
code1 { db close }
close [open test.db-shm w]
file attributes test.db-shm -permissions r--r--r--
code1 { sqlite3 db file:test.db?readonly_shm=1 }
csql1 { SELECT * FROM t1 }
} {1 {attempt to write a readonly database}}
do_test 1.3.2.4 {
code1 { sqlite3_extended_errcode db }
} {SQLITE_READONLY_RECOVERY}
}
finish_test