diff --git a/Makefile.msc b/Makefile.msc index c8658ed15e..4ea1341d7c 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1564,7 +1564,7 @@ $(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP) sqlite3.def: libsqlite3.lib echo EXPORTS > sqlite3.def dumpbin /all libsqlite3.lib \ - | $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset)?_[^@]*)(?:@\d+)?$$" \1 \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup)?_[^@]*)(?:@\d+)?$$" \1 \ | sort >> sqlite3.def # <> diff --git a/autoconf/Makefile.msc b/autoconf/Makefile.msc index ad88504be8..9f867986d7 100644 --- a/autoconf/Makefile.msc +++ b/autoconf/Makefile.msc @@ -21,7 +21,7 @@ TOP = . # Set this non-0 to enable full warnings (-W4, etc) when compiling. # !IFNDEF USE_FULLWARN -USE_FULLWARN = 0 +USE_FULLWARN = 1 !ENDIF # Set this non-0 to enable treating warnings as errors (-WX, etc) when @@ -954,7 +954,7 @@ Replace.exe: sqlite3.def: Replace.exe $(LIBOBJ) echo EXPORTS > sqlite3.def dumpbin /all $(LIBOBJ) \ - | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \ + | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \ | sort >> sqlite3.def $(SQLITE3EXE): $(TOP)\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H) diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c index 3d6616bd91..6dc9f8470e 100644 --- a/ext/fts5/fts5_index.c +++ b/ext/fts5/fts5_index.c @@ -4192,6 +4192,7 @@ static void fts5IndexMergeLevel( int bOldest; /* True if the output segment is the oldest */ int eDetail = p->pConfig->eDetail; const int flags = FTS5INDEX_QUERY_NOOUTPUT; + int bTermWritten = 0; /* True if current term already output */ assert( iLvlnLevel ); assert( pLvl->nMerge<=pLvl->nSeg ); @@ -4245,18 +4246,22 @@ static void fts5IndexMergeLevel( int nTerm; const u8 *pTerm; - /* Check for key annihilation. */ - if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue; - pTerm = fts5MultiIterTerm(pIter, &nTerm); if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){ if( pnRem && writer.nLeafWritten>nRem ){ break; } + fts5BufferSet(&p->rc, &term, nTerm, pTerm); + bTermWritten =0; + } + /* Check for key annihilation. */ + if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue; + + if( p->rc==SQLITE_OK && bTermWritten==0 ){ /* This is a new term. Append a term to the output segment. */ fts5WriteAppendTerm(p, &writer, nTerm, pTerm); - fts5BufferSet(&p->rc, &term, nTerm, pTerm); + bTermWritten = 1; } /* Append the rowid to the output */ diff --git a/ext/fts5/test/fts5delete.test b/ext/fts5/test/fts5delete.test new file mode 100644 index 0000000000..15d62c552d --- /dev/null +++ b/ext/fts5/test/fts5delete.test @@ -0,0 +1,54 @@ +# 2017 May 12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5delete + +# If SQLITE_ENABLE_FTS5 is not defined, omit this file. +ifcapable !fts5 { + finish_test + return +} +fts5_aux_test_functions db + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x); + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<5000 + ) + INSERT INTO t1(rowid, x) SELECT i, (i/2)*2 FROM s; +} + +do_test 1.1 { + execsql BEGIN + for {set i 1} {$i<=5000} {incr i} { + if {$i % 2} { + execsql { INSERT INTO t1 VALUES($i) } + } else { + execsql { DELETE FROM t1 WHERE rowid = $i } + } + } + execsql COMMIT +} {} + +do_test 1.2 { + execsql { INSERT INTO t1(t1, rank) VALUES('usermerge', 2); } + for {set i 0} {$i < 5} {incr i} { + execsql { INSERT INTO t1(t1, rank) VALUES('merge', 1) } + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } + } +} {} + +finish_test + diff --git a/ext/misc/json1.c b/ext/misc/json1.c index 2ef6e128eb..c1d2334a13 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -171,6 +171,7 @@ struct JsonParse { u8 oom; /* Set to true if out of memory */ u8 nErr; /* Number of errors seen */ u16 iDepth; /* Nesting depth */ + int nJson; /* Length of the zJson string in bytes */ }; /* @@ -413,6 +414,14 @@ static void jsonParseReset(JsonParse *pParse){ pParse->aUp = 0; } +/* +** Free a JsonParse object that was obtained from sqlite3_malloc(). +*/ +static void jsonParseFree(JsonParse *pParse){ + jsonParseReset(pParse); + sqlite3_free(pParse); +} + /* ** Convert the JsonNode pNode into a pure JSON string and ** append to pOut. Subsubstructure is also included. Return @@ -964,6 +973,49 @@ static int jsonParseFindParents(JsonParse *pParse){ return SQLITE_OK; } +/* +** Magic number used for the JSON parse cache in sqlite3_get_auxdata() +*/ +#define JSON_CACHE_ID (-429938) + +/* +** Obtain a complete parse of the JSON found in the first argument +** of the argv array. Use the sqlite3_get_auxdata() cache for this +** parse if it is available. If the cache is not available or if it +** is no longer valid, parse the JSON again and return the new parse, +** and also register the new parse so that it will be available for +** future sqlite3_get_auxdata() calls. +*/ +static JsonParse *jsonParseCached( + sqlite3_context *pCtx, + sqlite3_value **argv +){ + const char *zJson = (const char*)sqlite3_value_text(argv[0]); + int nJson = sqlite3_value_bytes(argv[0]); + JsonParse *p; + if( zJson==0 ) return 0; + p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); + if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){ + p->nErr = 0; + return p; /* The cached entry matches, so return it */ + } + p = sqlite3_malloc( sizeof(*p) + nJson + 1 ); + if( p==0 ){ + sqlite3_result_error_nomem(pCtx); + return 0; + } + memset(p, 0, sizeof(*p)); + p->zJson = (char*)&p[1]; + memcpy((char*)p->zJson, zJson, nJson+1); + if( jsonParse(p, pCtx, p->zJson) ){ + sqlite3_free(p); + return 0; + } + p->nJson = nJson; + sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree); + return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); +} + /* ** Compare the OBJECT label at pNode against zKey,nKey. Return true on ** a match. @@ -1329,29 +1381,30 @@ static void jsonArrayLengthFunc( int argc, sqlite3_value **argv ){ - JsonParse x; /* The parse */ + JsonParse *p; /* The parse */ sqlite3_int64 n = 0; u32 i; JsonNode *pNode; - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); + p = jsonParseCached(ctx, argv); + if( p==0 ) return; + assert( p->nNode ); if( argc==2 ){ const char *zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx); + pNode = jsonLookup(p, zPath, 0, ctx); }else{ - pNode = x.aNode; + pNode = p->aNode; } if( pNode==0 ){ - x.nErr = 1; - }else if( pNode->eType==JSON_ARRAY ){ + return; + } + if( pNode->eType==JSON_ARRAY ){ assert( (pNode->jnFlags & JNODE_APPEND)==0 ); for(i=1; i<=pNode->n; n++){ i += jsonNodeSize(&pNode[i]); } } - if( x.nErr==0 ) sqlite3_result_int64(ctx, n); - jsonParseReset(&x); + sqlite3_result_int64(ctx, n); } /* @@ -1367,20 +1420,21 @@ static void jsonExtractFunc( int argc, sqlite3_value **argv ){ - JsonParse x; /* The parse */ + JsonParse *p; /* The parse */ JsonNode *pNode; const char *zPath; JsonString jx; int i; if( argc<2 ) return; - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + p = jsonParseCached(ctx, argv); + if( p==0 ) return; jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=1; inErr ) break; if( argc>2 ){ jsonAppendSeparator(&jx); if( pNode ){ @@ -1398,7 +1452,6 @@ static void jsonExtractFunc( sqlite3_result_subtype(ctx, JSON_SUBTYPE); } jsonReset(&jx); - jsonParseReset(&x); } /* This is the RFC 7396 MergePatch algorithm. diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 8196e351bc..2f80af5644 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -3222,6 +3222,7 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ Rtree *pRtree = (Rtree *)pVtab; int iwt = pRtree->inWrTrans; + UNUSED_PARAMETER(iSavepoint); pRtree->inWrTrans = 0; nodeBlobReset(pRtree); pRtree->inWrTrans = iwt; diff --git a/manifest b/manifest index c5b72ddd17..fd41b85331 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -C Remove\sthe\stool/schemalint.tcl\sscript.\sAnd\srelated\sMakefile\sentries.\sIt\sis\nsuperseded\sby\ssqlite3_expert. -D 2017-05-04T14:02:05.547 +C Merge\schanges\sfrom\strunk. +D 2017-05-15T17:56:48.105 F Makefile.in 2594c46dc86cb8cf0bd397c89c16b946ba45cd8c3459471a8634a9a9412a4724 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 -F Makefile.msc 35879b76bc9136af684cc54b4178ebc6ab231ac0f24990bef703ad80a9330641 +F Makefile.msc 19636d6f00b600680edca5e437cd895599cffc11ceaa6ddac866373b98a9e644 F README.md 2b15fae33852f2f53996774c21fb41e1d94181c4401a0e43ac93e11f2cc901b9 F VERSION 0a0e02e16b44ea735b40118fc844311b2ab0d35b25fbeda5120aee62f973f663 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 @@ -11,7 +11,7 @@ F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90 F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2 F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903 F autoconf/Makefile.am 1a47d071e3d5435f8f7ebff7eb6703848bbd65d4 -F autoconf/Makefile.msc 1fba0d762d115509d4fce7e333305cee172d521aaacec8bbf7aad5503605d3fb +F autoconf/Makefile.msc 1014be616b420a5f48611d21b62ca2f50ec97ee795087ecb8a4d6bf6375ba11d F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7 F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1 F autoconf/configure.ac 2893b823ecc86cea13739f6c8109a41392254d1db08235c5615e0af5722c8578 @@ -111,7 +111,7 @@ F ext/fts5/fts5_buffer.c 4c1502d4c956cd092c89ce4480867f9d8bf325cd F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857 F ext/fts5/fts5_expr.c f2825f714d91bbe62ab5820aee9ad12e0c94205b2a01725eaa9072415ae9ff1c F ext/fts5/fts5_hash.c 880998e596b60f078348d48732ca4ad9a90caad2 -F ext/fts5/fts5_index.c dc25123df20c60492857de491a194dab4b46ace217b8483bda305d357bf6431d +F ext/fts5/fts5_index.c 9ce10106f42f8b84278a8ea859940224e2af5f0cc882f909364469f6f52769cb F ext/fts5/fts5_main.c 1ba0e7806886c1bc16e20d0dde1c2b535d1aeb98cbbb937c4c3e064af5ac6f03 F ext/fts5/fts5_storage.c 7750986004f3f0c94619a85ecb5dd6cbef53e5e3853488e8a906c269d4d11db6 F ext/fts5/fts5_tcl.c 4a901f00c8553740dba63511603f5527d741c26a @@ -150,6 +150,7 @@ F ext/fts5/test/fts5content.test 9a952c95518a14182dc3b59e3c8fa71cda82a4e1 F ext/fts5/test/fts5corrupt.test c2ad090192708150d50d961278df10ae7a4b8b62 F ext/fts5/test/fts5corrupt2.test 128eb6e2d26b09f4da339e581f424b3321e0fdaa F ext/fts5/test/fts5corrupt3.test f77f65e386231daf62902466b40ff998b2c8ce4f +F ext/fts5/test/fts5delete.test 0585395660889090a6a04b0cac0e70b16801da44ee321534d6169da49af8167f F ext/fts5/test/fts5detail.test ef5c690535a797413acaf5ad9b8ab5d49972df69 F ext/fts5/test/fts5determin.test 10648edb75ef1e196b10978fd21a9be0c31e09c3 F ext/fts5/test/fts5dlidx.test 007e9390c94638760797dbec2990c97c3fa08dfe @@ -225,7 +226,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25 F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c -F ext/misc/json1.c bd3bbdefb6024c5e40287d61cdf876587c18a6e60fbe8cd6bcdde10eefd14bb1 +F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984 F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33 F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e @@ -278,7 +279,7 @@ F ext/rbu/sqlite3rbu.c 2a89efba9eeba8e6c89a498dc195e8efbdde2694 F ext/rbu/sqlite3rbu.h 6fb6294c34a9ca93b5894a33bca530c6f08decba F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c 37c603c6b8aed1a760661ceb5a025bd36bac14cf56d59949bd8de14b2a17e9ed +F ext/rtree/rtree.c 8205d6e4466f766e57ce1b8aa38224ac9e1cec2d2bf4684cd1cc5a6ddf9b7014 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree1.test d5f0ba215b3bd1d05269ada86e74073b8445852aa0d33a63e10ec63a09c39473 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba @@ -347,7 +348,7 @@ F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c 3b23977620ce9662ac54443f65b87ba996e36121 F src/analyze.c 0d0ccf7520a201d8747ea2f02c92c26e26f801bc161f714f27b9f7630dde0421 F src/attach.c 8c476f8bd5d2afe11d925f890d30e527e5b0ce43 -F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792 +F src/auth.c 79f96c6f33bf0e5da8d1c282cee5ebb1852bb8a6ccca3e485d7c459b035d9c3c F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca @@ -360,12 +361,12 @@ F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 47d91a25ad8f199a71a5b1b7b169d6dd0d6e98c5719eca801568798743d1161c F src/date.c cc42a41c7422389860d40419a5e3bce5eaf6e7835c3ba2677751dc653550a5c7 F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d -F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c -F src/expr.c 965f5e6074ee61cf933be079c6a443c88414490c13ec270b5baaacaa920280fa +F src/delete.c 665e705641e5815c3f32d05820d1a5aa630274e568af73f377fdbc614fcf40b4 +F src/expr.c c83f799f3e5e3f3863bd0716119383e4a062d00a1e34e7273a78555918840a7c F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c db65492ae549c3b548c9ef1f279ce1684f1c473b116e1c56a90878cd5dcf968d F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174 -F src/global.c 4a34512d82fc5aa13c802db06bcfff5e1d3de955 +F src/global.c 8a6ab6b4d91effb96ffa81b39f0d70c862abca157f8aaa194600a4a8b7923344 F src/hash.c 63d0ee752a3b92d4695b2b1f5259c4621b2cfebd F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da @@ -373,7 +374,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c d4bb3a135948553d18cf992f76f7ed7b18aa0327f250607b5a6671e55d9947d5 F src/legacy.c e88ed13c2d531decde75d42c2e35623fb9ce3cb0 F src/loadext.c a72909474dadce771d3669bf84bf689424f6f87d471fee898589c3ef9b2acfd9 -F src/main.c ffb658429483c0d1c604014c631871f64b8db19666d8b70f75c7512d003ac1ad +F src/main.c 253de9f00311bd2b9898c93f22556a741e1a63310785c70356141326765fb64a F src/malloc.c e20bb2b48abec52d3faf01cce12e8b4f95973755fafec98d45162dfdab111978 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -395,7 +396,7 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 F src/os_unix.c 30e2c43e4955db990e5b5a81e901f8aa74cc8820 F src/os_win.c 2a6c73eef01c51a048cc4ddccd57f981afbec18a F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a -F src/pager.c ff1232b3088a39806035ecfac4fffeb22717d80b +F src/pager.c 80893c0860199aebc6efa4f102ab11eebde338b7fdbb0c04d4b04647c2fd62d1 F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa F src/parse.y 0513387ce02fea97897d8caef82d45f347818593f24f1bdc48e0c530a8af122d F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870 @@ -408,17 +409,17 @@ F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 3e518b962d932a997fae373366880fc028c75706 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac -F src/select.c 4f0adefaa5e9417459b07757e0f6060cac97930a86f0fba9797bab233ced66c0 -F src/shell.c 21b79c0e1b93f8e35fd7b4087d6ba438326c3d7e285d0dd51dfd741475f858a1 -F src/sqlite.h.in 8872d1f5e0f04bd441620ea6db856a84de219798a5d385b862a54d27892d68e8 +F src/select.c d74b1cde1d9ca6d08bec50b60a5be19440273646bc8ae16648d748c38161d5b7 +F src/shell.c a37d96b20b3644d0eb905df5aa7a0fcf9f6e73c15898337230c760a24a8df794 +F src/sqlite.h.in 1672a3a22b877d5fbd5d3d243591e11e241c5abc321dbf969429c4bf5656acd9 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28 F src/sqliteInt.h a8be6c63ce04fc759e3d8ca2dee2fa2d4128b0a4bf2031c3f6e482fd5c5abdfe F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 -F src/tclsqlite.c 2e0f7f63de8329526fbcb14fa5261d3574b2a06dd330f4df680120a3e6156133 -F src/test1.c 8a98191a1da8e100f77cdb5cc716df67d405028d +F src/tclsqlite.c d98070d60409b3a9d50bfea7c7275a14d01a0cdfba91c7eb46630e41efd2e3e1 +F src/test1.c c99f0442918a7a5d5b68a95d6024c211989e6c782c15ced5a558994baaf76a5e F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6 @@ -473,13 +474,13 @@ F src/treeview.c 6cf8d7fe9e63fae57dad1bb57f6615e14eac0c527e43d868e805042cae8ed1f F src/trigger.c 134b8e7b61317ab7b2a2dd12eb1b9aa2e23ac5bc4a05e63e35b3609b6b30a7c0 F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c -F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6 +F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23 F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569 F src/vdbe.c 356042d11e05064c43242020e8de97acef9fc8931cfc39ae7cf4cf91d6e42c19 F src/vdbe.h f7d1456e28875c2dcb964056589b5b7149ab7edf39edeca801596a39bb3d3848 -F src/vdbeInt.h c070bc5c8b913bda0ceaa995cd4d939ded5e4fc96cf7c3c1c602d41b871f8ade -F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860 -F src/vdbeaux.c dd4106907d8a52f80876c7cec030511220146056d0bb5d274f8528e251ffaed9 +F src/vdbeInt.h 1ecdacc1322fdd3241ec30c32a480e328a6f864e532dc53fae8e0ab68121aebf +F src/vdbeapi.c dc904b3c5e459727993c2421e653e29d63223846d129fae98adc782b0a996481 +F src/vdbeaux.c 73f10e298ed1e0565a30d8f8c909534ded5a32075a27542cc624d711ddcdc6b4 F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9 F src/vdbemem.c 2c70f8f5de6c71fb99a22c5b83be9fab5c47cdd8e279fa44a8c00cfed06d7e89 F src/vdbesort.c e72fe02a2121386ba767ede8942e9450878b8fc873abf3d1b6824485f092570c @@ -532,9 +533,9 @@ F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d F test/attach3.test c59d92791070c59272e00183b7353eeb94915976 F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0 -F test/auth.test c6ede04bee65637ff354b43fc1235aa560c0863e +F test/auth.test 3d6cd8f3978ba55b1202574e6ecd79c6e00914ca44b9bfd6c1fe6fb873fcac88 F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1 -F test/auth3.test 0d48b901cf111c14b4b1b5205c7d28f1a278190f +F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49 F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec F test/autoinc.test 6ae8fb69c9f656962464ae4e6667045d0dfc3b46 F test/autoindex1.test 14b63a9f1e405fe6d5bfc8c8d00249c2ebaf13ea @@ -715,7 +716,7 @@ F test/fkey1.test ba64806ff9a04eecab2679caad377ae99a5e94e4 F test/fkey2.test 155809016fad6b2a1491facf2ac53a551bc57c2c F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49 F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d -F test/fkey5.test 19a9b73bafd78323c37fc883dba060191541503d6094f8aea67fe94d33118e20 +F test/fkey5.test 24dd28eb3d9f1b5a174f47e9899ace5facb08373a4223593c8c631e6cf9f7d5a F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0 F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13 F test/fkey8.test e5372e32cdb4481f121ec3550703eeb7b4e0762c @@ -797,13 +798,13 @@ F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a F test/fts3expr3.test c4d4a7d6327418428c96e0a3a1137c251b8dfbf8 F test/fts3expr4.test c39a15d676b14fc439d9bf845aa7bddcf4a74dc3 F test/fts3expr5.test f9abfffbf5e53d48a33e12a1e8f8ba2c551c9b49 -F test/fts3fault.test 268e9589f44f49d6694ef39a293f0e0f80c6230fb01cc6f34325412acceb99ae +F test/fts3fault.test 3764ecffb3d341c5b05b3abe64153f385880035e67706ca2fc719e5d3352aedb F test/fts3fault2.test 536bbe01fe2946ec24b063a5eee813e8fd90354a6ca0b8f941d299c405edd17e F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 F test/fts3join.test 34750f3ce1e29b2749eaf0f1be2fa6301c5d50da F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6 F test/fts3matchinfo.test ce864e0bd92429df8008f31cf557269ba172482a -F test/fts3misc.test f481128013b9555babdf3bc04c58ab59d59bebc24b5f780f50342b9ffe05b547 +F test/fts3misc.test 66e7b59576ce2c795f0baff6d47f7f6f57e6f41101cf85fad05989e43bb060dd F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905 F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2 @@ -1174,6 +1175,7 @@ F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a F test/stat.test f8f1279ffffabe6df825723af18cc6e0ae70a893 F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1 F test/stmt.test 64844332db69cf1a735fcb3e11548557fc95392f +F test/subjournal.test 2121a93ef3d3e83d52bf236c8a02aef4009fbf52884754104b2b6cad9a041095 F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303 @@ -1518,7 +1520,7 @@ F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439 F tool/mkautoconfamal.sh e855df211ecbcc7131dee817110ff386cfb112f7 F tool/mkkeywordhash.c f7f3b342211ac6a14258b9726d5b97cf4f548f22 -F tool/mkmsvcmin.tcl 95b37e202cbed873aa8ffdbb493b9db45927be2b +F tool/mkmsvcmin.tcl cbd93f1cfa3a0a9ae56fc958510aa3fc3ac65e29cb111716199e3d0e66eefaa4 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl a01d2c1d8a6205b03fc635adf3735b4c523befd3 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e @@ -1526,11 +1528,11 @@ F tool/mkpragmatab.tcl 32bb40741df11bddc8451de9ea4d130e7b4476d8064794b1cf402ac11 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb F tool/mksqlite3c.tcl 06b2e6a0f21cc0a5d70fbbd136b3e0a96470645e -F tool/mksqlite3h.tcl b9836752c3d08f9fab2dfc0017ca9fd5d90ac863 +F tool/mksqlite3h.tcl 51bd5e7e840a920388a5966c9f2ccc618f434c57bd68c1bab4085b2553e1e237 F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5 F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091 -F tool/omittest.tcl 34d7ac01fe4fd18e3637f64abe12c40eca0f6b97 +F tool/omittest.tcl dfc8b18a23e9e5289104145b712cdb887c2d840c2d70dc09ce5dbeba8ed8d47c F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b F tool/replace.tcl 60f91e8dd06ab81f74d213ecbd9c9945f32ac048 @@ -1584,7 +1586,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 593e5dd00cdf8fbc680951d68b53b38262c61c467703f6a8eb477226cf6beedd -R bd679d9017e39a4713f5824e1924f07c -U dan -Z f03ecb4affa26d84072c6437b5574775 +P 269bf52e27611cd00fa7f73ee98b395a30dec215232cf1c34f6b741112ba530b bb0d9281588b8cc24bf2f1f10d0c56277004226adaa2ce5037782503b283b45d +R 7d3a8849d7369ade14c69fc7df3fcb28 +U drh +Z 969ec953bff5414f5fad1a53a1834b03 diff --git a/manifest.uuid b/manifest.uuid index fc8dafbb37..92a71c9011 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -269bf52e27611cd00fa7f73ee98b395a30dec215232cf1c34f6b741112ba530b \ No newline at end of file +6e0f64ab5eafda5d9e61e00c89af3c1ea2c5aa29821da1bdbcab040957b12403 \ No newline at end of file diff --git a/src/auth.c b/src/auth.c index 77a95d4a8f..dabc435b4a 100644 --- a/src/auth.c +++ b/src/auth.c @@ -216,6 +216,18 @@ int sqlite3AuthCheck( if( db->xAuth==0 ){ return SQLITE_OK; } + + /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the + ** callback are either NULL pointers or zero-terminated strings that + ** contain additional details about the action to be authorized. + ** + ** The following testcase() macros show that any of the 3rd through 6th + ** parameters can be either NULL or a string. */ + testcase( zArg1==0 ); + testcase( zArg2==0 ); + testcase( zArg3==0 ); + testcase( pParse->zAuthContext==0 ); + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser diff --git a/src/delete.c b/src/delete.c index 0683f9b9dd..03c3417358 100644 --- a/src/delete.c +++ b/src/delete.c @@ -350,7 +350,14 @@ void sqlite3DeleteFrom( /* Special case: A DELETE without a WHERE clause deletes everything. ** It is easier just to erase the whole table. Prior to version 3.6.5, ** this optimization caused the row change count (the value returned by - ** API function sqlite3_count_changes) to be set incorrectly. */ + ** API function sqlite3_count_changes) to be set incorrectly. + ** + ** The "rcauth==SQLITE_OK" terms is the + ** IMPLEMENATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and + ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but + ** the truncate optimization is disabled and all rows are deleted + ** individually. + */ if( rcauth==SQLITE_OK && pWhere==0 && !bComplex diff --git a/src/expr.c b/src/expr.c index a79b0b7495..8fc727fcd5 100644 --- a/src/expr.c +++ b/src/expr.c @@ -352,7 +352,6 @@ int sqlite3ExprVectorSize(Expr *pExpr){ } } -#ifndef SQLITE_OMIT_SUBQUERY /* ** Return a pointer to a subexpression of pVector that is the i-th ** column of the vector (numbered starting with 0). The caller must @@ -380,9 +379,7 @@ Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ } return pVector; } -#endif /* !defined(SQLITE_OMIT_SUBQUERY) */ -#ifndef SQLITE_OMIT_SUBQUERY /* ** Compute and return a new Expr object which when passed to ** sqlite3ExprCode() will generate all necessary code to compute @@ -440,7 +437,6 @@ Expr *sqlite3ExprForVectorField( } return pRet; } -#endif /* !define(SQLITE_OMIT_SUBQUERY) */ /* ** If expression pExpr is of type TK_SELECT, generate code to evaluate @@ -1550,7 +1546,7 @@ ExprList *sqlite3ExprListAppendVector( } } - if( pExpr->op==TK_SELECT && pList ){ + if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){ Expr *pFirst = pList->a[iFirst].pExpr; assert( pFirst!=0 ); assert( pFirst->op==TK_SELECT_COLUMN ); @@ -3411,7 +3407,11 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){ }else{ *piFreeable = 0; if( p->op==TK_SELECT ){ +#if SQLITE_OMIT_SUBQUERY + iResult = 0; +#else iResult = sqlite3CodeSubselect(pParse, p, 0, 0); +#endif }else{ int i; iResult = pParse->nMem+1; diff --git a/src/global.c b/src/global.c index a105135561..fe63bbe140 100644 --- a/src/global.c +++ b/src/global.c @@ -137,9 +137,16 @@ const unsigned char sqlite3CtypeMap[256] = { ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** SQLITE_USE_URI symbol defined. +** +** URI filenames are enabled by default if SQLITE_HAS_CODEC is +** enabled. */ #ifndef SQLITE_USE_URI -# define SQLITE_USE_URI 0 +# ifdef SQLITE_HAS_CODEC +# define SQLITE_USE_URI 1 +# else +# define SQLITE_USE_URI 0 +# endif #endif /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the diff --git a/src/main.c b/src/main.c index db508abc57..d39c49a73d 100644 --- a/src/main.c +++ b/src/main.c @@ -3096,16 +3096,18 @@ opendb_out: #endif #if defined(SQLITE_HAS_CODEC) if( rc==SQLITE_OK ){ - const char *zHexKey = sqlite3_uri_parameter(zOpen, "hexkey"); - if( zHexKey && zHexKey[0] ){ + const char *zKey; + if( (zKey = sqlite3_uri_parameter(zOpen, "hexkey"))!=0 && zKey[0] ){; u8 iByte; int i; - char zKey[40]; - for(i=0, iByte=0; isubjInMemory==0); +#endif assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ @@ -2381,14 +2386,34 @@ static int pager_playback_one_page( i64 ofst = (pgno-1)*(i64)pPager->pageSize; testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 ); assert( !pagerUseWal(pPager) ); + + /* Write the data read from the journal back into the database file. + ** This is usually safe even for an encrypted database - as the data + ** was encrypted before it was written to the journal file. The exception + ** is if the data was just read from an in-memory sub-journal. In that + ** case it must be encrypted here before it is copied into the database + ** file. */ +#ifdef SQLITE_HAS_CODEC + if( !jrnlEnc ){ + CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); + rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); + CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); + }else +#endif rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); + if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ - CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); +#ifdef SQLITE_HAS_CODEC + if( jrnlEnc ){ + CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); + sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); + CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData); + }else +#endif sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); - CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); } }else if( !isMainJrnl && pPg==0 ){ /* If this is a rollback of a savepoint and data was not written to @@ -2440,7 +2465,9 @@ static int pager_playback_one_page( } /* Decode the page just read from disk */ - CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); +#if SQLITE_HAS_CODEC + if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); } +#endif sqlite3PcacheRelease(pPg); } return rc; @@ -4452,8 +4479,13 @@ static int subjournalPage(PgHdr *pPg){ void *pData = pPg->pData; i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); char *pData2; - - CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + +#if SQLITE_HAS_CODEC + if( !pPager->subjInMemory ){ + CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + }else +#endif + pData2 = pData; PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); rc = write32bits(pPager->sjfd, offset, pPg->pgno); if( rc==SQLITE_OK ){ diff --git a/src/select.c b/src/select.c index 573a6fa11e..eabbcc8c94 100644 --- a/src/select.c +++ b/src/select.c @@ -5115,13 +5115,38 @@ int sqlite3Select( } #endif - /* Generate code for all sub-queries in the FROM clause + /* For each term in the FROM clause, do two things: + ** (1) Authorized unreferenced tables + ** (2) Generate code for all sub-queries */ -#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; inSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; SelectDest dest; - Select *pSub = pItem->pSelect; + Select *pSub; + + /* Issue SQLITE_READ authorizations with a fake column name for any tables that + ** are referenced but from which no values are extracted. Examples of where these + ** kinds of null SQLITE_READ authorizations would occur: + ** + ** SELECT count(*) FROM t1; -- SQLITE_READ t1."" + ** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2."" + ** + ** The fake column name is an empty string. It is possible for a table to + ** have a column named by the empty string, in which case there is no way to + ** distinguish between an unreferenced table and an actual reference to the + ** "" column. The original design was for the fake column name to be a NULL, + ** which would be unambiguous. But legacy authorization callbacks might + ** assume the column name is non-NULL and segfault. The use of an empty string + ** for the fake column name seems safer. + */ + if( pItem->colUsed==0 ){ + sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); + } + +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + /* Generate code for all sub-queries in the FROM clause + */ + pSub = pItem->pSelect; if( pSub==0 ) continue; /* Sometimes the code for a subquery will be generated more than @@ -5242,8 +5267,8 @@ int sqlite3Select( } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); - } #endif + } /* Various elements of the SELECT copied into local variables for ** convenience */ diff --git a/src/shell.c b/src/shell.c index 15c88061c2..d36f1fdd19 100644 --- a/src/shell.c +++ b/src/shell.c @@ -438,7 +438,7 @@ static void utf8_width_print(FILE *pOut, int w, const char *zUtf){ int n; int aw = w<0 ? -w : w; char zBuf[1000]; - if( aw>sizeof(zBuf)/3 ) aw = sizeof(zBuf)/3; + if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3; for(i=n=0; zUtf[i]; i++){ if( (zUtf[i]&0xc0)!=0x80 ){ n++; @@ -744,6 +744,10 @@ struct SHA3Context { unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */ }; +/* Allow the following routine to use the B0 variable, which is also +** a macro in the termios.h header file */ +#undef B0 + /* ** A single step of the Keccak mixing function for a 1600-bit state */ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 31c9d5c80f..74aa0f0050 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2684,6 +2684,7 @@ void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks ** METHOD: sqlite3 +** KEYWORDS: {authorizer callback} ** ** ^This routine registers an authorizer callback with a particular ** [database connection], supplied in the first argument. @@ -2711,8 +2712,10 @@ void sqlite3_randomness(int N, void *P); ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter ** to the callback is an integer [SQLITE_COPY | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters -** to the callback are zero-terminated strings that contain additional -** details about the action to be authorized. +** to the callback are either NULL pointers or zero-terminated strings +** that contain additional details about the action to be authorized. +** Applications must always be prepared to encounter a NULL pointer in any +** of the third through the sixth parameters of the authorization callback. ** ** ^If the action code is [SQLITE_READ] ** and the callback returns [SQLITE_IGNORE] then the @@ -2721,6 +2724,10 @@ void sqlite3_randomness(int N, void *P); ** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] ** return can be used to deny an untrusted user access to individual ** columns of a table. +** ^When a table is referenced by a [SELECT] but no column values are +** extracted from that table (for example in a query like +** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback +** is invoked once for that table with a column name that is an empty string. ** ^If the action code is [SQLITE_DELETE] and the callback returns ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the ** [truncate optimization] is disabled and all rows are deleted individually. @@ -4767,10 +4774,11 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata -** associated by the sqlite3_set_auxdata() function with the Nth argument -** value to the application-defined function. ^If there is no metadata -** associated with the function argument, this sqlite3_get_auxdata() interface +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata +** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument +** value to the application-defined function. ^N is zero for the left-most +** function argument. ^If there is no metadata +** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th @@ -4801,6 +4809,10 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** +** The value of the N parameter to these interfaces should be non-negative. +** Future enhancements may make use of negative N values to define new +** kinds of function caching behavior. +** ** These routines must be called from the same thread in which ** the SQL function is running. */ diff --git a/src/tclsqlite.c b/src/tclsqlite.c index a4a0ed3f30..5cdaa1147f 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -1033,9 +1033,16 @@ static int auth_callback( Tcl_DString str; int rc; const char *zReply; + /* EVIDENCE-OF: R-38590-62769 The first parameter to the authorizer + ** callback is a copy of the third parameter to the + ** sqlite3_set_authorizer() interface. + */ SqliteDb *pDb = (SqliteDb*)pArg; if( pDb->disableAuth ) return SQLITE_OK; + /* EVIDENCE-OF: R-56518-44310 The second parameter to the callback is an + ** integer action code that specifies the particular action to be + ** authorized. */ switch( code ){ case SQLITE_COPY : zCode="SQLITE_COPY"; break; case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; diff --git a/src/test1.c b/src/test1.c index d17fc1022a..87b255c9e9 100644 --- a/src/test1.c +++ b/src/test1.c @@ -4949,52 +4949,6 @@ static int SQLITE_TCLAPI test_interrupt( return TCL_OK; } -static u8 *sqlite3_stack_baseline = 0; - -/* -** Fill the stack with a known bitpattern. -*/ -static void prepStack(void){ - int i; - u32 bigBuf[65536]; - for(i=0; i=0 && ((u32*)sqlite3_stack_baseline)[-i]==0xdeadbeef; i--){} - Tcl_SetObjResult(interp, Tcl_NewIntObj(i*4)); - return TCL_OK; -} - /* ** Usage: sqlite_delete_function DB function-name ** @@ -7473,7 +7427,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite_delete_function", (Tcl_CmdProc*)delete_function }, { "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation }, { "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit }, - { "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used }, { "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout }, { "printf", (Tcl_CmdProc*)test_printf }, { "sqlite3IoTrace", (Tcl_CmdProc*)test_io_trace }, diff --git a/src/util.c b/src/util.c index 9b6f4f9e1d..7c9c5f54b7 100644 --- a/src/util.c +++ b/src/util.c @@ -713,6 +713,7 @@ int sqlite3GetInt32(const char *zNum, int *pValue){ } } #endif + if( !sqlite3Isdigit(zNum[0]) ) return 0; while( zNum[0]=='0' ) zNum++; for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ v = v*10 + c; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 6ef155b5c3..65e47c33f3 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -287,11 +287,11 @@ struct sqlite3_value { ** when the VM is halted (if not before). */ struct AuxData { - int iOp; /* Instruction number of OP_Function opcode */ - int iArg; /* Index of function argument. */ + int iAuxOp; /* Instruction number of OP_Function opcode */ + int iAuxArg; /* Index of function argument. */ void *pAux; /* Aux data pointer */ - void (*xDelete)(void *); /* Destructor for the aux data */ - AuxData *pNext; /* Next element in list */ + void (*xDeleteAux)(void*); /* Destructor for the aux data */ + AuxData *pNextAux; /* Next element in list */ }; /* diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 1f2699dc4d..bdc5f0320d 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -804,6 +804,12 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ /* ** Return the auxiliary data pointer, if any, for the iArg'th argument to ** the user-function defined by pCtx. +** +** The left-most argument is 0. +** +** Undocumented behavior: If iArg is negative then access a cache of +** auxiliary data pointers that is available to all functions within a +** single prepared statement. The iArg values must match. */ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; @@ -814,17 +820,24 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ #else assert( pCtx->pVdbe!=0 ); #endif - for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ - if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; + for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ + if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ + return pAuxData->pAux; + } } - - return (pAuxData ? pAuxData->pAux : 0); + return 0; } /* ** Set the auxiliary data pointer and delete function, for the iArg'th ** argument to the user-function defined by pCtx. Any previous value is ** deleted by calling the delete function specified when it was set. +** +** The left-most argument is 0. +** +** Undocumented behavior: If iArg is negative then make the data available +** to all functions within the current prepared statement using iArg as an +** access code. */ void sqlite3_set_auxdata( sqlite3_context *pCtx, @@ -836,33 +849,34 @@ void sqlite3_set_auxdata( Vdbe *pVdbe = pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - if( iArg<0 ) goto failed; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( pVdbe==0 ) goto failed; #else assert( pVdbe!=0 ); #endif - for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ - if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; + for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ + if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ + break; + } } if( pAuxData==0 ){ pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData)); if( !pAuxData ) goto failed; - pAuxData->iOp = pCtx->iOp; - pAuxData->iArg = iArg; - pAuxData->pNext = pVdbe->pAuxData; + pAuxData->iAuxOp = pCtx->iOp; + pAuxData->iAuxArg = iArg; + pAuxData->pNextAux = pVdbe->pAuxData; pVdbe->pAuxData = pAuxData; if( pCtx->fErrorOrAux==0 ){ pCtx->isError = 0; pCtx->fErrorOrAux = 1; } - }else if( pAuxData->xDelete ){ - pAuxData->xDelete(pAuxData->pAux); + }else if( pAuxData->xDeleteAux ){ + pAuxData->xDeleteAux(pAuxData->pAux); } pAuxData->pAux = pAux; - pAuxData->xDelete = xDelete; + pAuxData->xDeleteAux = xDelete; return; failed: diff --git a/src/vdbeaux.c b/src/vdbeaux.c index de9ea10cbb..87b1d16316 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2977,16 +2977,18 @@ void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){ while( *pp ){ AuxData *pAux = *pp; if( (iOp<0) - || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg)))) + || (pAux->iAuxOp==iOp + && pAux->iAuxArg>=0 + && (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg)))) ){ - testcase( pAux->iArg==31 ); - if( pAux->xDelete ){ - pAux->xDelete(pAux->pAux); + testcase( pAux->iAuxArg==31 ); + if( pAux->xDeleteAux ){ + pAux->xDeleteAux(pAux->pAux); } - *pp = pAux->pNext; + *pp = pAux->pNextAux; sqlite3DbFree(db, pAux); }else{ - pp= &pAux->pNext; + pp= &pAux->pNextAux; } } } diff --git a/test/auth.test b/test/auth.test index 0044fddebe..2487e568b2 100644 --- a/test/auth.test +++ b/test/auth.test @@ -36,12 +36,20 @@ proc_real proc {name arguments script} { do_test auth-1.1.1 { db close set ::DB [sqlite3 db test.db] + proc authx {code arg1 arg2 arg3 arg4 args} {return SQLITE_DENY} proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} { return SQLITE_DENY } return SQLITE_OK } + db authorizer ::authx + # EVIDENCE-OF: R-03993-24285 Only a single authorizer can be in place on + # a database connection at a time. Each call to sqlite3_set_authorizer + # overrides the previous call. + # + # The authx authorizer above is overridden by the auth authorizer below + # authx is never invoked. db authorizer ::auth catchsql {CREATE TABLE t1(a,b,c)} } {1 {not authorized}} @@ -60,6 +68,9 @@ do_test auth-1.1.4 { do_test auth-1.2 { execsql {SELECT name FROM sqlite_master} } {} +# EVIDENCE-OF: R-04452-49349 When the callback returns SQLITE_DENY, the +# sqlite3_prepare_v2() or equivalent call that triggered the authorizer +# will fail with an error message explaining that access is denied. do_test auth-1.3.1 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TABLE"} { @@ -312,6 +323,10 @@ ifcapable attach { } {1 {access to two.t2.b is prohibited}} execsql {DETACH DATABASE two} } +# EVIDENCE-OF: R-38392-49970 If the action code is SQLITE_READ and the +# callback returns SQLITE_IGNORE then the prepared statement statement +# is constructed to substitute a NULL value in place of the table column +# that would have been read if SQLITE_OK had been returned. do_test auth-1.36 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} { @@ -1606,6 +1621,8 @@ do_test auth-1.248 { set ::authargs } {COMMIT {} {} {}} do_test auth-1.249 { + # EVIDENCE-OF: R-52112-44167 Disable the authorizer by installing a NULL + # callback. db authorizer {} catchsql {ROLLBACK} } {0 {}} @@ -2478,6 +2495,57 @@ do_test auth-7.4 { SQLITE_READ t7 c main {} \ ] +# If a table is referenced but no columns are read from the table, +# that causes a single SQLITE_READ authorization with a NULL column +# name. +# +# EVIDENCE-OF: R-31520-16302 When a table is referenced by a SELECT but +# no column values are extracted from that table (for example in a query +# like "SELECT count(*) FROM tab") then the SQLITE_READ authorizer +# callback is invoked once for that table with a column name that is an +# empty string. +# +set ::authargs [list] +do_test auth-8.1 { + execsql {SELECT count(*) FROM t7} + set ::authargs +} [list \ + SQLITE_SELECT {} {} {} {} \ + SQLITE_FUNCTION {} count {} {} \ + SQLITE_READ t7 {} {} {} \ + ] +set ::authargs [list] + +do_test auth-8.2 { + execsql {SELECT t6.a FROM t6, t7} + set ::authargs +} [list \ + SQLITE_SELECT {} {} {} {} \ + SQLITE_READ t6 a main {} \ + SQLITE_READ t7 {} {} {} \ + ] + +# Test also that if SQLITE_DENY is returned from an SQLITE_READ authorizer +# invocation with no column name specified, compilation fails. +# +set ::authargs [list] +proc auth {op a b c d} { + lappend ::authargs $op $a $b $c $d + if {$op == "SQLITE_READ"} { return "SQLITE_DENY" } + return "SQLITE_OK" +} +set ::authargs [list] +do_catchsql_test auth-8.3 { + SELECT count(*) FROM t7 +} {1 {not authorized}} +do_test auth-8.4 { + set ::authargs +} [list \ + SQLITE_SELECT {} {} {} {} \ + SQLITE_FUNCTION {} count {} {} \ + SQLITE_READ t7 {} {} {} \ +] + rename proc {} rename proc_real proc diff --git a/test/auth3.test b/test/auth3.test index 013486e5a0..4377bcdc0f 100644 --- a/test/auth3.test +++ b/test/auth3.test @@ -53,6 +53,10 @@ do_test auth3.1.2 { set ::authcode SQLITE_DENY catchsql { DELETE FROM t1 } } {1 {not authorized}} +# EVIDENCE-OF: R-64962-58611 If the authorizer callback returns any +# value other than SQLITE_IGNORE, SQLITE_OK, or SQLITE_DENY then the +# sqlite3_prepare_v2() or equivalent call that triggered the authorizer +# will fail with an error message. do_test auth3.1.3 { set ::authcode SQLITE_INVALID catchsql { DELETE FROM t1 } diff --git a/test/fkey5.test b/test/fkey5.test index e9bb47f895..3c44cd319f 100644 --- a/test/fkey5.test +++ b/test/fkey5.test @@ -115,8 +115,11 @@ do_test fkey5-1.6 { # EVIDENCE-OF: R-55672-01620 The first column is the name of the table # that contains the REFERENCES clause. # -# EVIDENCE-OF: R-25219-25618 The second column is the rowid of the row -# that contains the invalid REFERENCES clause. +# EVIDENCE-OF: R-00471-55166 The second column is the rowid of the row +# that contains the invalid REFERENCES clause, or NULL if the child +# table is a WITHOUT ROWID table. +# +# The second clause in the previous is tested by fkey5-10.3. # # EVIDENCE-OF: R-40482-20265 The third column is the name of the table # that is referred to. @@ -407,6 +410,9 @@ do_execsql_test 10.1 { do_execsql_test 10.2 { PRAGMA foreign_key_check; } +# EVIDENCE-OF: R-00471-55166 The second column is the rowid of the row +# that contains the invalid REFERENCES clause, or NULL if the child +# table is a WITHOUT ROWID table. do_execsql_test 10.3 { INSERT INTO c30 VALUES(45, 45); PRAGMA foreign_key_check; diff --git a/test/fts3fault.test b/test/fts3fault.test index 2622e47136..56835f4e0e 100644 --- a/test/fts3fault.test +++ b/test/fts3fault.test @@ -177,13 +177,15 @@ do_test 8.0 { faultsim_save_and_close } {} -do_faultsim_test 8.1 -faults oom-t* -prep { - faultsim_restore_and_reopen - db func mit mit -} -body { - execsql { SELECT mit(matchinfo(t8, 'x')) FROM t8 WHERE t8 MATCH 'a b c' } -} -test { - faultsim_test_result {0 {{1 1 1 1 4 2 1 5 5}}} +ifcapable fts4_deferred { + do_faultsim_test 8.1 -faults oom-t* -prep { + faultsim_restore_and_reopen + db func mit mit + } -body { + execsql { SELECT mit(matchinfo(t8, 'x')) FROM t8 WHERE t8 MATCH 'a b c' } + } -test { + faultsim_test_result {0 {{1 1 1 1 4 2 1 5 5}}} + } } do_faultsim_test 8.2 -faults oom-t* -prep { diff --git a/test/fts3misc.test b/test/fts3misc.test index 0d003bd324..1fe0f500f7 100644 --- a/test/fts3misc.test +++ b/test/fts3misc.test @@ -147,30 +147,32 @@ do_execsql_test 3.1.5 { #------------------------------------------------------------------------- # reset_db -do_execsql_test 4.0 { - PRAGMA page_size = 512; - CREATE VIRTUAL TABLE t4 USING fts4; - WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<8000 ) - INSERT INTO t4 SELECT 'a b c a b c a b c' FROM s; +ifcapable fts4_deferred { + do_execsql_test 4.0 { + PRAGMA page_size = 512; + CREATE VIRTUAL TABLE t4 USING fts4; + WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<8000 ) + INSERT INTO t4 SELECT 'a b c a b c a b c' FROM s; + } + do_execsql_test 4.1 { + SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"' + } {8000} + do_execsql_test 4.2 { + SELECT quote(value) from t4_stat where id=0 + } {X'C03EC0B204C0A608'} + do_execsql_test 4.3 { + UPDATE t4_stat SET value = X'C03EC0B204C0A60800' WHERE id=0; + } + do_catchsql_test 4.4 { + SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"' + } {1 {database disk image is malformed}} + do_execsql_test 4.5 { + UPDATE t4_stat SET value = X'00C03EC0B204C0A608' WHERE id=0; + } + do_catchsql_test 4.6 { + SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"' + } {1 {database disk image is malformed}} } -do_execsql_test 4.1 { - SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"' -} {8000} -do_execsql_test 4.2 { - SELECT quote(value) from t4_stat where id=0 -} {X'C03EC0B204C0A608'} -do_execsql_test 4.3 { - UPDATE t4_stat SET value = X'C03EC0B204C0A60800' WHERE id=0; -} -do_catchsql_test 4.4 { - SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"' -} {1 {database disk image is malformed}} -do_execsql_test 4.5 { - UPDATE t4_stat SET value = X'00C03EC0B204C0A608' WHERE id=0; -} -do_catchsql_test 4.6 { - SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"' -} {1 {database disk image is malformed}} #------------------------------------------------------------------------- # diff --git a/test/subjournal.test b/test/subjournal.test new file mode 100644 index 0000000000..d4ea643c6e --- /dev/null +++ b/test/subjournal.test @@ -0,0 +1,70 @@ +# 2017 May 9 +# +# 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 subjournal + +do_execsql_test 1.0 { + PRAGMA temp_store = memory; + CREATE TABLE t1(a,b,c); + INSERT INTO t1 VALUES(1, 2, 3); +} {} +do_execsql_test 1.1 { + BEGIN; + INSERT INTO t1 VALUES(4, 5, 6); + SAVEPOINT one; + INSERT INTO t1 VALUES(7, 8, 9); + ROLLBACK TO one; + SELECT * FROM t1; +} {1 2 3 4 5 6} +do_execsql_test 1.2 { + COMMIT; +} + +do_execsql_test 2.0 { + PRAGMA cache_size = 5; + CREATE TABLE t2(a BLOB); + CREATE INDEX i2 ON t2(a); + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 + ) INSERT INTO t2 SELECT randomblob(500) FROM s; +} + +do_test 2.1 { + forcedelete test.db2 + sqlite3 db2 test2.db + sqlite3_backup B db2 main db main + set nPage [db one {PRAGMA page_count}] + B step [expr $nPage-10] +} {SQLITE_OK} + +do_execsql_test 2.2 { + BEGIN; + UPDATE t2 SET a=randomblob(499); + SAVEPOINT two; + UPDATE t2 SET a=randomblob(498); + ROLLBACK TO two; + COMMIT; + PRAGMA integrity_check; +} {ok} + +do_test 2.3 { + B step 1000 +} {SQLITE_DONE} +do_test 2.4 { + B finish + execsql { PRAGMA integrity_check } db2 +} {ok} + +finish_test + diff --git a/tool/mkmsvcmin.tcl b/tool/mkmsvcmin.tcl index bdd02be1fb..8d5729865c 100644 --- a/tool/mkmsvcmin.tcl +++ b/tool/mkmsvcmin.tcl @@ -83,7 +83,7 @@ Replace.exe: sqlite3.def: Replace.exe $(LIBOBJ) echo EXPORTS > sqlite3.def dumpbin /all $(LIBOBJ) \\ - | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \\ + | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \\ | sort >> sqlite3.def }]] diff --git a/tool/mksqlite3h.tcl b/tool/mksqlite3h.tcl index 9d307d1b1e..5106a83857 100644 --- a/tool/mksqlite3h.tcl +++ b/tool/mksqlite3h.tcl @@ -81,6 +81,9 @@ set declpattern2 \ set declpattern3 \ {^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3changeset_[_a-zA-Z0-9]+)(\(.*)$} +set declpattern4 \ + {^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3changegroup_[_a-zA-Z0-9]+)(\(.*)$} + # Force the output to use unix line endings, even on Windows. fconfigure stdout -translation lf @@ -129,7 +132,8 @@ foreach file $filelist { } else { if {[regexp $declpattern1 $line all rettype funcname rest] || \ [regexp $declpattern2 $line all rettype funcname rest] || \ - [regexp $declpattern3 $line all rettype funcname rest]} { + [regexp $declpattern3 $line all rettype funcname rest] || \ + [regexp $declpattern4 $line all rettype funcname rest]} { set line SQLITE_API append line " " [string trim $rettype] if {[string index $rettype end] ne "*"} { diff --git a/tool/omittest.tcl b/tool/omittest.tcl index 5437f2eb01..c42519dd8c 100644 --- a/tool/omittest.tcl +++ b/tool/omittest.tcl @@ -1,6 +1,3 @@ - -set rcsid {$Id: omittest.tcl,v 1.8 2008/10/13 15:35:09 drh Exp $} - # Documentation for this script. This may be output to stderr # if the script is invoked incorrectly. set ::USAGE_MESSAGE { @@ -134,26 +131,37 @@ proc process_options {argv} { set ::TARGET testfixture ;# Default thing to build for {set i 0} {$i < [llength $argv]} {incr i} { - switch -- [lindex $argv $i] { - -makefile { + switch -regexp -- [lindex $argv $i] { + -{1,2}makefile { incr i set ::MAKEFILE [lindex $argv $i] } - -nmake { + -{1,2}nmake { set ::MAKEBIN nmake set ::MAKEFILE ./Makefile.msc } - -target { + -{1,2}target { incr i set ::TARGET [lindex $argv $i] } - -skip_run { + -{1,2}skip_run { set ::SKIP_RUN 1 } + -{1,2}help { + puts $::USAGE_MESSAGE + exit + } + + -.* { + puts stderr "Unknown option: [lindex $argv i]" + puts stderr $::USAGE_MESSAGE + exit 1 + } + default { if {[info exists ::SYMBOL]} { puts stderr [string trim $::USAGE_MESSAGE]