Index: ext/fts3/fts3.c ================================================================== --- ext/fts3/fts3.c +++ ext/fts3/fts3.c @@ -642,10 +642,13 @@ rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_step(pStmt); p->nPgsz = sqlite3_column_int(pStmt, 0); rc = sqlite3_finalize(pStmt); + }else if( rc==SQLITE_AUTH ){ + p->nPgsz = 1024; + rc = SQLITE_OK; } } assert( p->nPgsz>0 || rc!=SQLITE_OK ); sqlite3_free(zSql); *pRc = rc; Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -5515,10 +5515,15 @@ Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = printExplainQueryPlan(pStmt); + /* This is needed on Windows so that a test case using this + ** function can open a read pipe and get the output of + ** printExplainQueryPlan() immediately. + */ + fflush(stdout); Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } #endif /* SQLITE_OMIT_EXPLAIN */ Index: src/test_vfs.c ================================================================== --- src/test_vfs.c +++ src/test_vfs.c @@ -1068,11 +1068,10 @@ case CMD_SCRIPT: { if( objc==3 ){ int nByte; if( p->pScript ){ - int i; Tcl_DecrRefCount(p->pScript); p->pScript = 0; } Tcl_GetStringFromObj(objv[2], &nByte); if( nByte>0 ){ @@ -1221,11 +1220,10 @@ return TCL_OK; } static void testvfs_obj_del(ClientData cd){ Testvfs *p = (Testvfs *)cd; - int i; if( p->pScript ) Tcl_DecrRefCount(p->pScript); sqlite3_vfs_unregister(p->pVfs); ckfree((char *)p->pVfs); ckfree((char *)p); } Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -457,10 +457,18 @@ rc = db->errCode = p->rc; } return (rc&db->errMask); } +/* +** The maximum number of times that a statement will try to reparse +** itself before giving up and returning SQLITE_SCHEMA. +*/ +#ifndef SQLITE_MAX_SCHEMA_RETRY +# define SQLITE_MAX_SCHEMA_RETRY 5 +#endif + /* ** This is the top-level implementation of sqlite3_step(). Call ** sqlite3Step() to do most of the work. If a schema error occurs, ** call sqlite3Reprepare() and try again. */ @@ -475,11 +483,11 @@ return SQLITE_MISUSE_BKPT; } db = v->db; sqlite3_mutex_enter(db->mutex); while( (rc = sqlite3Step(v))==SQLITE_SCHEMA - && cnt++ < 5 + && cnt++ < SQLITE_MAX_SCHEMA_RETRY && (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){ sqlite3_reset(pStmt); v->expired = 0; } if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){ Index: test/fts4aa.test ================================================================== --- test/fts4aa.test +++ test/fts4aa.test @@ -20,13 +20,15 @@ ifcapable !fts3 { 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.'); INSERT INTO t1(docid,words) VALUES(1001003,'And God said, Let there be light: and there was light.'); INSERT INTO t1(docid,words) VALUES(1001004,'And God saw the light, that it was good: and God divided the light from the darkness.'); @@ -1559,13 +1561,45 @@ INSERT INTO t1(docid,words) VALUES(1050024,'And Joseph said unto his brethren, I die: and God will surely visit you, and bring you out of this land unto the land which he sware to Abraham, to Isaac, and to Jacob.'); INSERT INTO t1(docid,words) VALUES(1050025,'And Joseph took an oath of the children of Israel, saying, God will surely visit you, and ye shall carry up my bones from hence.'); INSERT INTO t1(docid,words) VALUES(1050026,'So Joseph died, being an hundred and ten years old: and they embalmed him, and he was put in a coffin in Egypt.'); COMMIT; } +} + +# 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 } } {} @@ -1581,53 +1615,116 @@ binary scan $blob $scan($::tcl_platform(byteOrder)) r return $r } db func mit mit -do_test fts4aa-2.1 { +do_test fts4aa-1.3 { db eval { 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, '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, '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 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, 'pcxnal')) FROM t1 WHERE t1 MATCH 'joseph died in egypt' ORDER BY docid; } } {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 Index: test/oserror.test ================================================================== --- test/oserror.test +++ test/oserror.test @@ -49,10 +49,11 @@ # The xOpen() method of the unix VFS calls getcwd() as well as open(). # Although this does not appear to be documented in the man page, on OSX # 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 { for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 } } msg] $msg Index: test/triggerC.test ================================================================== --- test/triggerC.test +++ test/triggerC.test @@ -226,26 +226,26 @@ } } $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 " CREATE TABLE t23(x PRIMARY KEY); Index: test/wal5.test ================================================================== --- test/wal5.test +++ test/wal5.test @@ -233,11 +233,18 @@ do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2} do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {} 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 # if they cannot obtain those locks. There are three locks that a checkpoint # may block on (in the following order): Index: tool/omittest.tcl ================================================================== --- tool/omittest.tcl +++ tool/omittest.tcl @@ -29,12 +29,12 @@ * The makefile should support the variable "OPTS" as a way to pass options from the make command line to lemon and the C compiler. More precisely, the following two invocations must be supported: - make -f $::MAKEFILE testfixture OPTS="-DSQLITE_OMIT_ALTERTABLE=1" - make -f $::MAKEFILE test + $::MAKEBIN -f $::MAKEFILE testfixture OPTS="-DSQLITE_OMIT_ALTERTABLE=1" + $::MAKEBIN -f $::MAKEFILE test Makefiles generated by the sqlite configure program cannot be used as they do not respect the OPTS variable. } @@ -71,11 +71,11 @@ catch { file copy -force ./config.h $dir file copy -force ./libtool $dir } set rc [catch { - exec make -C $dir -f $::MAKEFILE $target OPTS=$opts >& $dir/build.log + exec $::MAKEBIN -C $dir -f $::MAKEFILE clean $target OPTS=$opts >& $dir/build.log }] if {$rc} { puts "No good. See $dir/build.log." return } else { @@ -100,11 +100,11 @@ } else { # Run the test suite. puts -nonewline "Testing $dir..." flush stdout set rc [catch { - exec make -C $dir -f $::MAKEFILE test OPTS=$opts >& $dir/test.log + exec $::MAKEBIN -C $dir -f $::MAKEFILE test OPTS=$opts >& $dir/test.log }] if {$rc} { puts "No good. See $dir/test.log." } else { puts "Ok" @@ -117,12 +117,13 @@ # Currently the only option supported is "-makefile", default # "../Makefile.linux-gcc". Set the ::MAKEFILE variable to the value of this # option. # proc process_options {argv} { + set ::MAKEBIN make ;# Default value if {$::tcl_platform(platform)=="windows" || $::tcl_platform(platform)=="os2"} { - set ::MAKEFILE ./Makefile ;# Default value + set ::MAKEFILE ./Makefile ;# Default value on Windows and OS2 } else { set ::MAKEFILE ./Makefile.linux-gcc ;# Default value } set ::SKIP_RUN 0 ;# Default to attempt test @@ -131,10 +132,15 @@ -makefile { incr i set ::MAKEFILE [lindex $argv $i] } + -nmake { + set ::MAKEBIN nmake + set ::MAKEFILE ./Makefile.msc + } + -skip_run { set ::SKIP_RUN 1 } default { @@ -249,11 +255,11 @@ if {[lsearch $::OMIT_SYMBOLS $sym]<0 && [lsearch $::ENABLE_SYMBOLS $sym]<0} { puts stderr "No such symbol: $sym" exit -1 } - set dirname "test_[string range $sym 7 end]" + set dirname "test_[regsub -nocase {^x*SQLITE_} $sym {}]" run_quick_test $dirname $sym } else { # First try a test with all OMIT symbols except SQLITE_OMIT_FLOATING_POINT # and SQLITE_OMIT_PRAGMA defined. The former doesn't work (causes segfaults) # and the latter is currently incompatible with the test suite (this should @@ -268,19 +274,19 @@ # Now try one quick.test with each of the OMIT symbols defined. Included # are the OMIT_FLOATING_POINT and OMIT_PRAGMA symbols, even though we # know they will fail. It's good to be reminded of this from time to time. foreach sym $::OMIT_SYMBOLS { - set dirname "test_[string range $sym 7 end]" + set dirname "test_[regsub -nocase {^x*SQLITE_} $sym {}]" run_quick_test $dirname $sym } # Try the ENABLE/DISABLE symbols one at a time. # We don't do them all at once since some are conflicting. foreach sym $::ENABLE_SYMBOLS { - set dirname "test_[string range $sym 7 end]" + set dirname "test_[regsub -nocase {^x*SQLITE_} $sym {}]" run_quick_test $dirname $sym } } } main $argv