Index: ext/fts3/fts3_write.c ================================================================== --- ext/fts3/fts3_write.c +++ ext/fts3/fts3_write.c @@ -3795,18 +3795,18 @@ memset(p, 0, sizeof(NodeReader)); p->aNode = aNode; p->nNode = nNode; /* Figure out if this is a leaf or an internal node. */ - if( p->aNode[0] ){ + if( aNode && aNode[0] ){ /* An internal node. */ p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild); }else{ p->iOff = 1; } - return nodeReaderNext(p); + return aNode ? nodeReaderNext(p) : SQLITE_OK; } /* ** This function is called while writing an FTS segment each time a leaf o ** node is finished and written to disk. The key (zTerm/nTerm) is guaranteed @@ -4294,12 +4294,12 @@ for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){ NodeReader reader; pNode = &pWriter->aNodeWriter[i]; - rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n); - if( reader.aNode ){ + if( pNode->block.a){ + rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n); while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); blobGrowBuffer(&pNode->key, reader.term.n, &rc); if( rc==SQLITE_OK ){ memcpy(pNode->key.a, reader.term.a, reader.term.n); pNode->key.n = reader.term.n; Index: src/loadext.c ================================================================== --- src/loadext.c +++ src/loadext.c @@ -461,11 +461,15 @@ #endif /* Version 3.28.0 and later */ sqlite3_stmt_isexplain, sqlite3_value_frombind, /* Version 3.30.0 and later */ +#ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_drop_modules, +#else + 0, +#endif }; /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a Index: src/mutex.h ================================================================== --- src/mutex.h +++ src/mutex.h @@ -65,6 +65,7 @@ #define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexEnd() #define MUTEX_LOGIC(X) #else #define MUTEX_LOGIC(X) X +int sqlite3_mutex_held(sqlite3_mutex*); #endif /* defined(SQLITE_MUTEX_OMIT) */ Index: src/shell.c.in ================================================================== --- src/shell.c.in +++ src/shell.c.in @@ -9417,11 +9417,11 @@ sqlite3_trace_v2(p->db, mType, sql_trace_callback, p); } }else #endif /* !defined(SQLITE_OMIT_TRACE) */ -#ifdef SQLITE_DEBUG +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE) if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){ int ii; int lenOpt; char *zOpt; if( nArg<2 ){ Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -1129,11 +1129,13 @@ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; +#ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_drop_modules(db, argc>2 ? (const char**)(argv+2) : 0); +#endif return TCL_OK; } /* ** Routines to implement the x_count() aggregate function. Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -552,11 +552,11 @@ printf(" ir:%lld", p->u.i); }else if( p->flags & MEM_Int ){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT }else if( p->flags & MEM_Real ){ - printf(" r:%g", p->u.r); + printf(" r:%.17g", p->u.r); #endif }else if( sqlite3VdbeMemIsRowSet(p) ){ printf(" (rowset)"); }else{ char zBuf[200]; Index: test/affinity2.test ================================================================== --- test/affinity2.test +++ test/affinity2.test @@ -116,16 +116,21 @@ SELECT * FROM t0 WHERE +-+'ce' >= t0.c0; } {-1 {}} # 2019-08-30 ticket https://www.sqlite.org/src/info/40812aea1fde9594 # -do_execsql_test 600 { - DROP TABLE IF EXISTS t0; - CREATE TABLE t0(c0 REAL UNIQUE); - INSERT INTO t0(c0) VALUES (3175546974276630385); - SELECT 3175546974276630385 < c0 FROM t0; -} {1} -do_execsql_test 601 { - SELECT 1 FROM t0 WHERE 3175546974276630385 < c0; -} {1} +# Due to some differences in floating point computations, these tests do not +# work under valgrind. +# +if {![info exists ::G(valgrind)]} { + do_execsql_test 600 { + DROP TABLE IF EXISTS t0; + CREATE TABLE t0(c0 REAL UNIQUE); + INSERT INTO t0(c0) VALUES (3175546974276630385); + SELECT 3175546974276630385 < c0 FROM t0; + } {1} + do_execsql_test 601 { + SELECT 1 FROM t0 WHERE 3175546974276630385 < c0; + } {1} +} finish_test Index: test/corruptM.test ================================================================== --- test/corruptM.test +++ test/corruptM.test @@ -19,10 +19,20 @@ set testprefix corruptM # These tests deal with corrupt database files # database_may_be_corrupt + +proc open_db2_and_catchsql {sql} { + set rc [catch { sqlite3 db2 test.db } msg] + if {$rc} { + return [list $rc $msg] + } + set res [catchsql $sql db2] + db2 close + set res +} db close forcedelete test.db sqlite3 db test.db do_execsql_test corruptM-100 { @@ -36,167 +46,141 @@ do_execsql_test corruptM-101 { PRAGMA writable_schema=on; UPDATE sqlite_master SET tbl_name=NULL WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 {} | index i1 t1 | view v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-102 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; - } db2 + } } {1 {malformed database schema (t1)}} -db2 close do_execsql_test corruptM-110 { UPDATE sqlite_master SET tbl_name='tx' WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 tx | index i1 t1 | view v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-111 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; - } db2 + } } {1 {malformed database schema (t1)}} -db2 close do_execsql_test corruptM-112 { UPDATE sqlite_master SET tbl_name='t1', type='tabl' WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {tabl t1 t1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-113 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; - } db2 + } } {1 {malformed database schema (t1)}} -db2 close do_execsql_test corruptM-114 { UPDATE sqlite_master SET tbl_name='t9',type='table',name='t9'WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t9 t9 | index i1 t1 | view v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-114 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; - } db2 + } } {1 {malformed database schema (t9)}} -db2 close do_execsql_test corruptM-120 { UPDATE sqlite_master SET name='t1',tbl_name='T1' WHERE name='t9'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 T1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-121 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; - } db2 + } } {0 {ok 111 222 333 15 22}} -db2 close do_execsql_test corruptM-130 { UPDATE sqlite_master SET type='view' WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {view t1 T1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-131 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; - } db2 + } } {1 {malformed database schema (t1)}} -db2 close do_execsql_test corruptM-140 { UPDATE sqlite_master SET type='table', tbl_name='t1' WHERE name='t1'; UPDATE sqlite_master SET tbl_name='tx' WHERE name='i1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 tx | view v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-141 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; - } db2 + } } {1 {malformed database schema (i1)}} -db2 close do_execsql_test corruptM-150 { UPDATE sqlite_master SET type='table', tbl_name='t1' WHERE name='i1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | table i1 t1 | view v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-151 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; - } db2 + } } {1 {malformed database schema (i1)}} -db2 close do_execsql_test corruptM-160 { UPDATE sqlite_master SET type='view', tbl_name='t1' WHERE name='i1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | view i1 t1 | view v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-161 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; - } db2 + } } {1 {malformed database schema (i1)}} -db2 close do_execsql_test corruptM-170 { UPDATE sqlite_master SET type='index', tbl_name='t1' WHERE name='i1'; UPDATE sqlite_master SET type='table', tbl_name='v2' WHERE name='v2'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 t1 | table v2 v2 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-171 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; - } db2 + } } {1 {malformed database schema (v2)}} -db2 close do_execsql_test corruptM-180 { UPDATE sqlite_master SET type='view',name='v3',tbl_name='v3' WHERE name='v2'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 t1 | view v3 v3 | trigger r1 t1 |} -sqlite3 db2 test.db do_test corruptM-181 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; - } db2 + } } {1 {malformed database schema (v3)}} -db2 close do_execsql_test corruptM-190 { UPDATE sqlite_master SET type='view',name='v2',tbl_name='v2' WHERE name='v3'; UPDATE sqlite_master SET type='view' WHERE name='r1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 t1 | view v2 v2 | view r1 t1 |} -sqlite3 db2 test.db do_test corruptM-191 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; - } db2 + } } {1 {malformed database schema (r1)}} -db2 close do_execsql_test corruptM-192 { UPDATE sqlite_master SET type='trigger',tbl_name='v2' WHERE name='r1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 t1 | view v2 v2 | trigger r1 v2 |} -sqlite3 db2 test.db do_test corruptM-193 { - catchsql { + open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; - } db2 + } } {1 {malformed database schema (r1)}} -db2 close finish_test ADDED test/fts4merge5.test Index: test/fts4merge5.test ================================================================== --- test/fts4merge5.test +++ test/fts4merge5.test @@ -0,0 +1,58 @@ +# 2019 October 02 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS4 module. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fts4merge5 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +source $testdir/genesis.tcl + +do_execsql_test 1.1 { + CREATE TABLE t1(docid, words); +} +fts_kjv_genesis + +do_execsql_test 1.2 { + CREATE VIRTUAL TABLE x1 USING fts3; + INSERT INTO x1(x1) VALUES('nodesize=64'); + INSERT INTO x1(x1) VALUES('maxpending=64'); +} + +do_execsql_test 1.3 { + INSERT INTO x1(docid, content) SELECT * FROM t1; +} + +for {set tn 1} {1} {incr tn} { + set tc1 [db total_changes] + do_execsql_test 1.4.$tn.1 { + INSERT INTO x1(x1) VALUES('merge=1,2'); + } + set tc2 [db total_changes] + + if {($tc2 - $tc1)<2} break + + do_execsql_test 1.4.$tn.1 { + INSERT INTO x1(x1) VALUES('integrity-check'); + } +} + + + +finish_test Index: test/permutations.test ================================================================== --- test/permutations.test +++ test/permutations.test @@ -124,10 +124,11 @@ sort3.test sort4.test fts4growth.test fts4growth2.test bigsort.test walprotocol.test mmap4.test fuzzer2.test walcrash2.test e_fkey.test backup.test fts4merge.test fts4merge2.test fts4merge4.test fts4check.test + fts4merge5.test fts3cov.test fts3snippet.test fts3corrupt2.test fts3an.test fts3defer.test fts4langid.test fts3sort.test fts5unicode.test rtree4.test }] @@ -453,12 +454,12 @@ test_suite "coverage-analyze" -description { Coverage tests for file analyze.c. } -files { analyze3.test analyze4.test analyze5.test analyze6.test - analyze7.test analyze8.test analyze9.test analyzeA.test - analyze.test analyzeB.test mallocA.test + analyze7.test analyze8.test analyze9.test + analyze.test mallocA.test } test_suite "coverage-sorter" -description { Coverage tests for file vdbesort.c. } -files { @@ -622,11 +623,11 @@ } -presql { pragma encoding = 'UTF-16' } -files { alter.test alter3.test analyze.test analyze3.test analyze4.test analyze5.test analyze6.test - analyze7.test analyze8.test analyze9.test analyzeA.test analyzeB.test + analyze7.test analyze8.test analyze9.test auth.test bind.test blob.test capi2.test capi3.test collate1.test collate2.test collate3.test collate4.test collate5.test collate6.test conflict.test date.test delete.test expr.test fkey1.test func.test hook.test index.test insert2.test insert.test interrupt.test in.test intpkey.test ioerr.test join2.test join.test lastinsert.test Index: test/releasetest.tcl ================================================================== --- test/releasetest.tcl +++ test/releasetest.tcl @@ -409,10 +409,12 @@ } } if {[regexp {runtime error: +(.*)} $line all msg]} { # skip over "value is outside range" errors if {[regexp {value .* is outside the range of representable} $line]} { + # noop + } elseif {[regexp {overflow: .* cannot be represented} $line]} { # noop } else { incr ::NERRCASE if {$rc==0} { set rc 1 Index: test/wapptest.tcl ================================================================== --- test/wapptest.tcl +++ test/wapptest.tcl @@ -823,12 +823,17 @@ } else { lappend lTestArg $arg } } +wapptest_init for {set i 0} {$i < [llength $lTestArg]} {incr i} { - switch -- [lindex $lTestArg $i] { + set opt [lindex $lTestArg $i] + if {[string range $opt 0 1]=="--"} { + set opt [string range $opt 1 end] + } + switch -- $opt { -platform { if {$i==[llength $lTestArg]-1} { wapptest_usage } incr i set arg [lindex $lTestArg $i] set lPlatform [releasetest_data platforms] @@ -880,14 +885,13 @@ wapptest_usage } } } -wapptest_init if {$G(noui)==0} { wapp-start $lWappArg } else { wapptest_run do_some_stuff vwait forever } Index: test/without_rowid1.test ================================================================== --- test/without_rowid1.test +++ test/without_rowid1.test @@ -14,10 +14,14 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix without_rowid1 + +proc do_execsql_test_if_vtab {tn sql {res {}}} { + ifcapable vtab { uplevel [list do_execsql_test $tn $sql $res] } +} # Create and query a WITHOUT ROWID table. # do_execsql_test without_rowid1-1.0 { CREATE TABLE t1(a,b,c,d, PRIMARY KEY(c,a)) WITHOUT ROWID; @@ -29,11 +33,11 @@ SELECT *, '|' FROM t1 ORDER BY c, a; } {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic juliet flipper command | journal sherman gamma patriot |} integrity_check without_rowid1-1.0ic -do_execsql_test without_rowid1-1.0ixi { +do_execsql_test_if_vtab without_rowid1-1.0ixi { SELECT name, key FROM pragma_index_xinfo('t1'); } {c 1 a 1 b 0 d 0} do_execsql_test without_rowid1-1.1 { SELECT *, '|' FROM t1 ORDER BY +c, a; @@ -117,11 +121,11 @@ } {abc def} do_execsql_test 2.1.2 { UPDATE t4 SET a = 'ABC'; SELECT * FROM t4; } {ABC def} -do_execsql_test 2.1.3 { +do_execsql_test_if_vtab 2.1.3 { SELECT name, coll, key FROM pragma_index_xinfo('t4'); } {a nocase 1 b BINARY 0} do_execsql_test 2.2.1 { DROP TABLE t4; @@ -133,11 +137,11 @@ do_execsql_test 2.2.2 { UPDATE t4 SET a = 'ABC', b = 'xyz'; SELECT * FROM t4; } {xyz ABC} -do_execsql_test 2.2.3 { +do_execsql_test_if_vtab 2.2.3 { SELECT name, coll, key FROM pragma_index_xinfo('t4'); } {a nocase 1 b BINARY 0} do_execsql_test 2.3.1 { @@ -144,11 +148,11 @@ CREATE TABLE t5 (a, b, PRIMARY KEY(b, a)) WITHOUT ROWID; INSERT INTO t5(a, b) VALUES('abc', 'def'); UPDATE t5 SET a='abc', b='def'; } {} -do_execsql_test 2.3.2 { +do_execsql_test_if_vtab 2.3.2 { SELECT name, coll, key FROM pragma_index_xinfo('t5'); } {b BINARY 1 a BINARY 1} do_execsql_test 2.4.1 { @@ -163,11 +167,11 @@ do_execsql_test 2.4.2 { SELECT * FROM t6 ORDER BY b, a; SELECT * FROM t6 ORDER BY c; } {ABC def ghi ABC def ghi} -do_execsql_test 2.4.3 { +do_execsql_test_if_vtab 2.4.3 { SELECT name, coll, key FROM pragma_index_xinfo('t6'); } {b BINARY 1 a nocase 1 c BINARY 0} #------------------------------------------------------------------------- Index: test/without_rowid6.test ================================================================== --- test/without_rowid6.test +++ test/without_rowid6.test @@ -13,20 +13,24 @@ # has redundant columns. # set testdir [file dirname $argv0] source $testdir/tester.tcl + +proc do_execsql_test_if_vtab {tn sql {res {}}} { + ifcapable vtab { uplevel [list do_execsql_test $tn $sql $res] } +} do_execsql_test without_rowid6-100 { CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,a,b,c,d,a,b,c)) WITHOUT ROWID; CREATE INDEX t1a ON t1(b, b); WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<1000) INSERT INTO t1(a,b,c,d,e) SELECT i, i+1000, printf('x%dy',i), 0, 0 FROM c; ANALYZE; } {} -do_execsql_test without_rowid6-101 { +do_execsql_test_if_vtab without_rowid6-101 { SELECT name, key FROM pragma_index_xinfo('t1'); } {a 1 b 1 c 1 d 1 e 0} do_execsql_test without_rowid6-110 { SELECT c FROM t1 WHERE a=123; } {x123y} @@ -52,11 +56,11 @@ PRIMARY KEY(b) ) WITHOUT ROWID; INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); SELECT a FROM t1 WHERE b>3 ORDER BY b; } {4 1} -do_execsql_test without_rowid6-201 { +do_execsql_test_if_vtab without_rowid6-201 { SELECT name, key FROM pragma_index_xinfo('t1'); } {b 1 a 0 c 0} do_execsql_test without_rowid6-210 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; @@ -109,11 +113,11 @@ PRIMARY KEY(b,c) ) WITHOUT ROWID; INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); SELECT a FROM t1 WHERE b>3 ORDER BY b; } {4 1} -do_execsql_test without_rowid6-501 { +do_execsql_test_if_vtab without_rowid6-501 { SELECT name, key FROM pragma_index_xinfo('t1'); } {b 1 c 1 a 0} do_execsql_test without_rowid6-510 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; Index: test/without_rowid7.test ================================================================== --- test/without_rowid7.test +++ test/without_rowid7.test @@ -12,10 +12,14 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix without_rowid7 + +proc do_execsql_test_if_vtab {tn sql {res {}}} { + ifcapable vtab { uplevel [list do_execsql_test $tn $sql $res] } +} do_execsql_test 1.0 { CREATE TABLE t1(a, b COLLATE nocase, PRIMARY KEY(a, a, b)) WITHOUT ROWID; } @@ -34,17 +38,17 @@ } {one} do_execsql_test 2.2a { PRAGMA index_info(t2); } {0 0 a 1 0 a} -do_execsql_test 2.2b { +do_execsql_test_if_vtab 2.2b { SELECT *, '|' FROM pragma_index_info('t2'); } {0 0 a | 1 0 a |} do_execsql_test 2.3a { PRAGMA index_xinfo(t2); } {0 0 a 0 nocase 1 1 0 a 0 BINARY 1 2 1 b 0 BINARY 0} -do_execsql_test 2.3b { +do_execsql_test_if_vtab 2.3b { SELECT *, '|' FROM pragma_index_xinfo('t2'); } {0 0 a 0 nocase 1 | 1 0 a 0 BINARY 1 | 2 1 b 0 BINARY 0 |} do_execsql_test 2.4 { CREATE TABLE t3(a, b, PRIMARY KEY(a COLLATE nocase, a));